epubforge 0.0.5 → 0.0.6
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/VERSION +1 -1
- data/config/actions/init.rb +2 -3
- data/config/actions/kindle.rb +3 -3
- data/config/actions/mobify.rb +69 -0
- data/config/htmlizers.rb +8 -0
- data/lib/action/run_description.rb +56 -6
- data/lib/action/runner.rb +5 -9
- data/lib/action/thor_action.rb +32 -4
- data/lib/core_extensions/kernel.rb +0 -20
- data/lib/custom_helpers.rb +28 -27
- data/lib/epub/assets/image.rb +2 -3
- data/lib/epub/assets/page.rb +33 -6
- data/lib/epub/assets/xhtml.rb +8 -0
- data/lib/epub/builder.rb +47 -18
- data/lib/epubforge.rb +2 -1
- data/lib/utils/class_loader.rb +1 -2
- data/lib/utils/file_orderer.rb +9 -9
- data/lib/utils/file_path.rb +1 -1
- data/lib/utils/html_translator.rb +2 -1
- data/lib/utils/htmlizer.rb +1 -1
- data/templates/default/book/cover.xhtml.template +13 -0
- data/templates/default/notes/images/cover.png +0 -0
- data/templates/default/settings/config.rb.form +1 -1
- data/test/test_epubforge.rb +10 -9
- metadata +7 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.6
|
data/config/actions/init.rb
CHANGED
@@ -15,7 +15,7 @@ module EpubForge
|
|
15
15
|
|
16
16
|
@template_dir = EpubForge.root.join( "templates", @template_to_use )
|
17
17
|
src_entries = @template_dir.glob( "**", "*" ).map{ |entry|
|
18
|
-
entry.
|
18
|
+
entry.relative_path_from( @template_dir )
|
19
19
|
}
|
20
20
|
|
21
21
|
self.source_paths.push( @template_dir )
|
@@ -74,7 +74,7 @@ module EpubForge
|
|
74
74
|
configure_git( opts[:git] || {} )
|
75
75
|
end
|
76
76
|
else
|
77
|
-
|
77
|
+
warn("The program 'git' must be installed and locatable if you want epubforge to back up your project.")
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
@@ -121,7 +121,6 @@ module EpubForge
|
|
121
121
|
end
|
122
122
|
|
123
123
|
self.destination_root_filepath = root.fwf_filepath
|
124
|
-
debugger if self.destination_root_filepath != root.fwf_filepath.expand
|
125
124
|
|
126
125
|
if self.destination_root_filepath.exist? &&
|
127
126
|
(!(self.destination_root_filepath.empty?) || !(self.destination_root_filepath.directory?))
|
data/config/actions/kindle.rb
CHANGED
@@ -4,6 +4,7 @@ module EpubForge
|
|
4
4
|
description "Create a .mobi book and try to push it to your Kindle (conversion requires Calibre)"
|
5
5
|
keywords :kindle, :push, :b2k
|
6
6
|
usage "#{$PROGRAM_NAME} b2k <project_directory>"
|
7
|
+
# requires_executable "ebook-convert"
|
7
8
|
|
8
9
|
# TODO: Hard-coded. Need a global settings file?
|
9
10
|
KINDLE_DEVICE_DIR = "/".fwf_filepath.join( "Volumes", "Kindle" )
|
@@ -15,7 +16,6 @@ module EpubForge
|
|
15
16
|
@src_epub = @project.filename_for_epub_book.fwf_filepath
|
16
17
|
@dst_mobi = @project.filename_for_mobi_book.fwf_filepath
|
17
18
|
|
18
|
-
mobify
|
19
19
|
end
|
20
20
|
|
21
21
|
protected
|
@@ -31,8 +31,8 @@ module EpubForge
|
|
31
31
|
say_all_is_well "Formatted for Kindle (.mobi file). File at #{@dst_mobi}."
|
32
32
|
push_to_device @dst_mobi
|
33
33
|
else
|
34
|
-
|
35
|
-
|
34
|
+
warn( "Something went wrong during the conversion process." )
|
35
|
+
warn( "#{@dst_mobi} exists, but may not be complete or correct." ) if @dst_mobi.exist?
|
36
36
|
false
|
37
37
|
end
|
38
38
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module EpubForge
|
2
|
+
module Action
|
3
|
+
class Mobify < ThorAction
|
4
|
+
description "Create a .mobi book and try to push it to your Kindle (conversion requires Calibre)"
|
5
|
+
keywords :mobify
|
6
|
+
usage "#{$PROGRAM_NAME} mobify <project_directory(optional)>"
|
7
|
+
# requires_executable "ebook-convert", "ebook-convert is included as part of the Calibre ebook management software."
|
8
|
+
|
9
|
+
desc( "do:kindle", "Turn your .epub file into a .mobi file. Check to see if your Kindle is connected, then pushes it." )
|
10
|
+
def do( project, *args )
|
11
|
+
@project = project
|
12
|
+
@src_epub = @project.filename_for_epub_book.fwf_filepath
|
13
|
+
@dst_mobi = @project.filename_for_mobi_book.fwf_filepath
|
14
|
+
|
15
|
+
@args = args
|
16
|
+
|
17
|
+
mobify
|
18
|
+
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
def mobify
|
24
|
+
return false unless fulfill_requirements
|
25
|
+
|
26
|
+
say "converting from #{@src_epub} to #{@dst_mobi}"
|
27
|
+
cmd = "ebook-convert #{@src_epub} #{@dst_mobi}"
|
28
|
+
say "executing: #{cmd}"
|
29
|
+
`#{cmd}`
|
30
|
+
|
31
|
+
if $?.success? && @dst_mobi.exist?
|
32
|
+
say_all_is_well "Formatted for Kindle (.mobi file). File at #{@dst_mobi}."
|
33
|
+
push_to_device @dst_mobi
|
34
|
+
else
|
35
|
+
warn( "Something went wrong during the conversion process." )
|
36
|
+
warn( "#{@dst_mobi} exists, but may not be complete or correct." ) if @dst_mobi.exist?
|
37
|
+
false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def push_to_device mobi_file
|
42
|
+
if KINDLE_DEVICE_DIR.directory? && KINDLE_PUSH_DIR.directory?
|
43
|
+
FileUtils.copy( mobi_file, KINDLE_PUSH_DIR )
|
44
|
+
say_all_is_well "File pushed to Kindle."
|
45
|
+
true
|
46
|
+
else
|
47
|
+
say_error "NOT installed on Kindle. It may not be plugged in."
|
48
|
+
false
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def fulfill_requirements
|
53
|
+
unless ebook_convert_installed?
|
54
|
+
say_error( "ebook-convert is not installed. Quitting." )
|
55
|
+
return false
|
56
|
+
end
|
57
|
+
|
58
|
+
BookToEpub.new.do( @project )
|
59
|
+
|
60
|
+
unless @src_epub.exist?
|
61
|
+
say_error( "Cannot find source .epub #{src_epub}" )
|
62
|
+
return false
|
63
|
+
end
|
64
|
+
|
65
|
+
true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/config/htmlizers.rb
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
EpubForge::Utils::Htmlizer.define do |html|
|
2
|
+
html.format :xhtml
|
3
|
+
html.group :default
|
4
|
+
html.executable "false"
|
5
|
+
html.cmd "cat {{f}}"
|
6
|
+
end
|
7
|
+
|
8
|
+
|
1
9
|
EpubForge::Utils::Htmlizer.define do |html|
|
2
10
|
html.format :markdown
|
3
11
|
html.group :default # the default is :user, so user-defined ones don't have to set it
|
@@ -1,11 +1,13 @@
|
|
1
1
|
module EpubForge
|
2
2
|
module Action
|
3
3
|
class RunDescription
|
4
|
-
attr_accessor :args
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
attr_accessor :args,
|
5
|
+
:project,
|
6
|
+
:keyword,
|
7
|
+
:klass,
|
8
|
+
:errors,
|
9
|
+
:state,
|
10
|
+
:execution_returned
|
9
11
|
|
10
12
|
def initialize
|
11
13
|
@args = nil
|
@@ -13,10 +15,58 @@ module EpubForge
|
|
13
15
|
@keyword = nil
|
14
16
|
@klass = nil
|
15
17
|
@errors = []
|
18
|
+
@state = :initialized
|
16
19
|
end
|
20
|
+
|
21
|
+
def run
|
22
|
+
if self.runnable?
|
23
|
+
handle_errors do
|
24
|
+
@execution_returned = self.klass.new.do( self.project, *(self.args) )
|
25
|
+
end
|
26
|
+
else
|
27
|
+
puts "Error(s) trying to complete the requested action:"
|
28
|
+
puts self.errors.join("\n")
|
29
|
+
end
|
30
|
+
|
31
|
+
self.finish
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def handle_errors &block
|
36
|
+
yield
|
37
|
+
rescue Exception => e
|
38
|
+
@errors << "#{e.class}: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
17
42
|
|
18
43
|
def runnable?
|
19
|
-
|
44
|
+
! errors?
|
45
|
+
end
|
46
|
+
|
47
|
+
def errors?
|
48
|
+
!@errors.epf_blank?
|
49
|
+
end
|
50
|
+
|
51
|
+
def success?
|
52
|
+
finished? && ! errors?
|
53
|
+
end
|
54
|
+
|
55
|
+
def finished?
|
56
|
+
@state == :finished
|
57
|
+
end
|
58
|
+
|
59
|
+
def finish
|
60
|
+
@state = :finished
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_s
|
64
|
+
str = "RunDescription:\n"
|
65
|
+
[ :args, :project, :keyword, :klass, :errors, :state ].each do |data|
|
66
|
+
str << "#{data} : #{self.send(data)}\n"
|
67
|
+
end
|
68
|
+
|
69
|
+
str
|
20
70
|
end
|
21
71
|
end
|
22
72
|
end
|
data/lib/action/runner.rb
CHANGED
@@ -17,12 +17,9 @@ module EpubForge
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def run
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
puts "Error(s) trying to complete the requested action:"
|
24
|
-
puts @run_description.errors.join("\n")
|
25
|
-
end
|
20
|
+
@run_description.run
|
21
|
+
puts @run_description
|
22
|
+
@run_description
|
26
23
|
end
|
27
24
|
|
28
25
|
# order: project_dir(optional), keyword, args
|
@@ -36,9 +33,6 @@ module EpubForge
|
|
36
33
|
# print help message if no keywords given
|
37
34
|
parse_args
|
38
35
|
|
39
|
-
# finish setting up run_description
|
40
|
-
@run_description.args = @args
|
41
|
-
|
42
36
|
run
|
43
37
|
end
|
44
38
|
|
@@ -86,6 +80,8 @@ module EpubForge
|
|
86
80
|
|
87
81
|
if !existing_project && @run_description.klass.project_required?
|
88
82
|
@run_description.errors << "Could not find a project directory, but the action #{@run_description.klass} requires one. Current directory is not an epubforge project."
|
83
|
+
else
|
84
|
+
@run_description.args = @args
|
89
85
|
end
|
90
86
|
end
|
91
87
|
|
data/lib/action/thor_action.rb
CHANGED
@@ -40,6 +40,9 @@ module EpubForge
|
|
40
40
|
include Thor::Actions
|
41
41
|
extend SharedActionInterface
|
42
42
|
|
43
|
+
method_option :verbose, :type => :boolean, :default => false, :aliases => "-v"
|
44
|
+
method_option :debug, :type => :boolean, :default => false, :aliases => "--dbg"
|
45
|
+
|
43
46
|
|
44
47
|
CLEAR = Thor::Shell::Color::CLEAR
|
45
48
|
RED = Thor::Shell::Color::RED
|
@@ -52,6 +55,14 @@ module EpubForge
|
|
52
55
|
|
53
56
|
|
54
57
|
protected
|
58
|
+
def say_when_verbose( *args )
|
59
|
+
say( *args ) if @verbose
|
60
|
+
end
|
61
|
+
|
62
|
+
def say_when_debugging( *args )
|
63
|
+
say( *args ) if @debug
|
64
|
+
end
|
65
|
+
|
55
66
|
def say_error( statement )
|
56
67
|
say( "ERROR : #{statement}", RED + ON_BLUE )
|
57
68
|
end
|
@@ -64,10 +75,6 @@ module EpubForge
|
|
64
75
|
say( statement, GREEN )
|
65
76
|
end
|
66
77
|
|
67
|
-
def say_in_warning( statement )
|
68
|
-
warn( statement, RED )
|
69
|
-
end
|
70
|
-
|
71
78
|
def say_subtly( statement )
|
72
79
|
say( statement, MAGENTA )
|
73
80
|
end
|
@@ -133,6 +140,27 @@ module EpubForge
|
|
133
140
|
@executables[name]
|
134
141
|
end
|
135
142
|
|
143
|
+
def requirements
|
144
|
+
@requirements ||= []
|
145
|
+
end
|
146
|
+
|
147
|
+
def add_requirement( *args, &block )
|
148
|
+
@requirements ||= []
|
149
|
+
@requirements.push( [args, block] )
|
150
|
+
end
|
151
|
+
|
152
|
+
def requires_executable( ex, fail_msg )
|
153
|
+
add_requirement( ex, fail_msg ) do
|
154
|
+
executable_installed?( ex, fail_msg )
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def must_target_a_project( project_dir )
|
159
|
+
add_requirement( project_dir ) do
|
160
|
+
Project.is_project_dir?( project_dir )
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
136
164
|
def git_installed?
|
137
165
|
executable_installed?('git')
|
138
166
|
end
|
@@ -1,24 +1,4 @@
|
|
1
1
|
module Kernel
|
2
|
-
# def puts_nowhere( &block )
|
3
|
-
# collect_stdout( "/dev/null", &block )
|
4
|
-
# end
|
5
|
-
#
|
6
|
-
# def collect_stdout( dest, &block )
|
7
|
-
# @puts_nowhere_keep_old_stdout ||= []
|
8
|
-
# @puts_nowhere_keep_old_stdout << $stdout
|
9
|
-
# if dest.is_a?(String)
|
10
|
-
# $stdout = File.open( dest, "w" )
|
11
|
-
# else
|
12
|
-
# $stdout = dest
|
13
|
-
# end
|
14
|
-
#
|
15
|
-
# $stdout.sync = true
|
16
|
-
#
|
17
|
-
# yield
|
18
|
-
#
|
19
|
-
# $stdout = @puts_nowhere_keep_old_stdout.pop
|
20
|
-
# end
|
21
|
-
|
22
2
|
# yields an alternate reality block where instance methods
|
23
3
|
# are different from what they were. At the end of the block
|
24
4
|
# it resets the initial values of the instance variables.
|
data/lib/custom_helpers.rb
CHANGED
@@ -27,33 +27,34 @@ module EpubForge
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def collect_stdout( dest = StringIO.new, &block )
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
30
|
+
raise ArgumentError.new("No block given.") unless block_given?
|
31
|
+
|
32
|
+
prior_stdout = $stdout
|
33
|
+
# @epf_prior_stdout_stack ||= []
|
34
|
+
# @epf_prior_stdout_stack << $stdout
|
35
|
+
|
36
|
+
$stdout = begin
|
37
|
+
if dest.is_a?( String ) || dest.is_a?( Pathname )
|
38
|
+
File.open( dest, "a" )
|
39
|
+
elsif dest.is_a?( IO ) || dest.is_a?( StringIO )
|
40
|
+
dest
|
41
|
+
else
|
42
|
+
raise ArgumentError.new("collect_stdout cannot take a <#{dest.class.name}> as an argument.")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
$stdout.sync = true
|
47
|
+
yield
|
48
|
+
|
49
|
+
$stdout = prior_stdout
|
50
|
+
|
51
|
+
dest.is_a?( StringIO ) ? dest.string : nil
|
52
|
+
end
|
53
|
+
|
54
|
+
# def collect_stdout( *args, &block )
|
55
|
+
# yield
|
56
|
+
# ""
|
57
|
+
# end
|
57
58
|
end
|
58
59
|
end
|
59
60
|
|
data/lib/epub/assets/image.rb
CHANGED
@@ -5,12 +5,11 @@ module EpubForge
|
|
5
5
|
attr_reader :ext, :filename, :name
|
6
6
|
def initialize( filename, options = {} )
|
7
7
|
@filename = filename.fwf_filepath
|
8
|
-
@name
|
9
|
-
@ext = @filename.extname.gsub( /^\./, "" )
|
8
|
+
@name, @ext = @filename.basename_and_ext
|
10
9
|
end
|
11
10
|
|
12
11
|
def link
|
13
|
-
IMAGES_DIR.join( @name
|
12
|
+
IMAGES_DIR.join( "#{@name}.#{@ext}" )
|
14
13
|
end
|
15
14
|
end
|
16
15
|
end
|
data/lib/epub/assets/page.rb
CHANGED
@@ -2,30 +2,57 @@ module EpubForge
|
|
2
2
|
module Epub
|
3
3
|
module Assets
|
4
4
|
class Page < Asset
|
5
|
-
attr_reader :html, :original_file, :title, :project, :media_type, :dest_extension
|
6
|
-
|
5
|
+
attr_reader :html, :original_file, :title, :project, :media_type, :dest_extension, :dest_filename
|
6
|
+
attr_reader :section_id
|
7
7
|
|
8
8
|
def initialize file, metadata, project
|
9
9
|
raise "NIL" if project.nil?
|
10
|
+
|
11
|
+
@original_file = file.fwf_filepath
|
10
12
|
|
11
13
|
@metadata = metadata
|
12
14
|
@project = project
|
13
|
-
@original_file = file
|
14
15
|
@dest_extension = "xhtml"
|
16
|
+
@section_id = @original_file.basename_no_ext
|
17
|
+
@dest_filename = "#{@section_id}.#{@dest_extension}"
|
15
18
|
|
16
|
-
|
17
|
-
|
19
|
+
get_html
|
20
|
+
get_title
|
21
|
+
|
18
22
|
@content = ""
|
23
|
+
@cover = false
|
19
24
|
puts "Initialized #{file} with title [#{@title}]"
|
20
25
|
end
|
21
26
|
|
27
|
+
def get_html
|
28
|
+
@html = Utils::Htmlizer.instance.translate( @original_file )
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_title
|
32
|
+
@title = @original_file.basename.to_s.split(".")[0..-2].map(&:capitalize).join(" : ")
|
33
|
+
end
|
34
|
+
|
22
35
|
def link
|
23
|
-
TEXT_DIR.join( "
|
36
|
+
TEXT_DIR.join( "#{@section_id}.#{@dest_extension}" )
|
24
37
|
end
|
25
38
|
|
26
39
|
def media_type
|
27
40
|
MEDIA_TYPES[@dest_extension]
|
28
41
|
end
|
42
|
+
|
43
|
+
def cover( val = nil )
|
44
|
+
unless val.nil?
|
45
|
+
@cover = val
|
46
|
+
end
|
47
|
+
@cover
|
48
|
+
end
|
49
|
+
|
50
|
+
def cover_asset( val = nil )
|
51
|
+
unless val.nil?
|
52
|
+
@cover = val
|
53
|
+
end
|
54
|
+
@cover
|
55
|
+
end
|
29
56
|
end
|
30
57
|
end
|
31
58
|
end
|
data/lib/epub/builder.rb
CHANGED
@@ -3,7 +3,7 @@ XmlBuilder = Builder
|
|
3
3
|
|
4
4
|
module EpubForge
|
5
5
|
module Epub
|
6
|
-
PAGE_FILE_EXTENSIONS = %w(html markdown textile)
|
6
|
+
PAGE_FILE_EXTENSIONS = %w(html markdown textile xhtml)
|
7
7
|
IMAGE_FILE_EXTENSIONS = %w(jpg png gif)
|
8
8
|
|
9
9
|
MEDIA_TYPES = { "gif" => "image/gif", "jpg" => "image/jpeg", "png" => "image/png",
|
@@ -26,12 +26,12 @@ module EpubForge
|
|
26
26
|
@book_dir = @project.target_dir.join( @book_dir_short ).fwf_filepath
|
27
27
|
@config = @project.config
|
28
28
|
|
29
|
-
@config
|
29
|
+
@config.page_orderer = Utils::FileOrderer.new( opts[:page_order] || @config.pages[@book_dir_short] )
|
30
30
|
|
31
|
-
@metadata = @config
|
31
|
+
@metadata = @config.metadata || {}
|
32
32
|
|
33
33
|
page_files = @book_dir.glob( ext: PAGE_FILE_EXTENSIONS )
|
34
|
-
@section_files = @config
|
34
|
+
@section_files = @config.page_orderer.reorder( page_files )
|
35
35
|
|
36
36
|
@sections = @section_files.map do |section|
|
37
37
|
case section.to_s.split(".").last
|
@@ -41,21 +41,42 @@ module EpubForge
|
|
41
41
|
Assets::HTML.new( section, @metadata, self )
|
42
42
|
when "textile"
|
43
43
|
Assets::Textile.new( section, @metadata, self )
|
44
|
+
when "xhtml"
|
45
|
+
Assets::XHTML.new( section, @metadata, self ) # These files are inserted into the book unaltered
|
44
46
|
else
|
45
47
|
raise "UNKNOWN EXTENSION TYPE"
|
46
48
|
end
|
47
49
|
end
|
48
50
|
|
49
|
-
@sections.each_with_index{ |sec, i| sec.section_number = i }
|
51
|
+
# @sections.each_with_index{ |sec, i| sec.section_number = i }
|
50
52
|
|
51
53
|
images = @book_dir.glob( "images", ext: IMAGE_FILE_EXTENSIONS )
|
52
54
|
@images = images.map{ |img| Assets::Image.new(img) }
|
53
|
-
|
55
|
+
|
54
56
|
@stylesheets = @book_dir.glob( "stylesheets", "*.css" ).map do |sheet|
|
55
57
|
Assets::Stylesheet.new( sheet )
|
56
58
|
end
|
57
59
|
|
58
|
-
|
60
|
+
install_cover
|
61
|
+
|
62
|
+
@scratch_dir = FunWith::Files::FilePath.tmpdir.join( "ebookdir" )
|
63
|
+
end
|
64
|
+
|
65
|
+
def install_cover
|
66
|
+
# Existing cover is moved to the very front
|
67
|
+
if cover_section = @sections.detect{|sec| sec.original_file.basename_no_ext.match( /^cover$/ ) }
|
68
|
+
cover_section.cover( true )
|
69
|
+
elsif cover_image = @images.find{ |img| img.name == "cover" }
|
70
|
+
# actually install cover
|
71
|
+
contents = "<div id='cover'><img class='cover' src='#{cover_image.link.relative_path_from(TEXT_DIR)}' alt='#{@metadata.name}, by #{@metadata.author}'/></div>"
|
72
|
+
cover_file = @project.book_dir.join( "cover.xhtml" )
|
73
|
+
cover_file.write( wrap_page( contents ) )
|
74
|
+
cover_section = Assets::Page.new( cover_file, @metadata, @project )
|
75
|
+
@sections.unshift( cover_section )
|
76
|
+
puts "cover page generated"
|
77
|
+
else
|
78
|
+
return false
|
79
|
+
end
|
59
80
|
end
|
60
81
|
|
61
82
|
def toc
|
@@ -76,6 +97,7 @@ module EpubForge
|
|
76
97
|
b.meta :name => "dtb:depth", :content => "1"
|
77
98
|
b.meta :name => "dtb:totalPageCount", :content => "0"
|
78
99
|
b.meta :name => "dtb:maxPageNumber", :content=> "0"
|
100
|
+
|
79
101
|
end
|
80
102
|
|
81
103
|
# <docTitle>
|
@@ -98,7 +120,7 @@ module EpubForge
|
|
98
120
|
b.navLabel do
|
99
121
|
b.text section.title
|
100
122
|
end
|
101
|
-
b.content :src => section.link
|
123
|
+
b.content :src => section.link.relative_path_from( "/OEBPS" )
|
102
124
|
end
|
103
125
|
end
|
104
126
|
end
|
@@ -157,6 +179,11 @@ module EpubForge
|
|
157
179
|
b.dc :publisher, @metadata["publisher"] || "A Pack of Orangutans"
|
158
180
|
b.dc :date, {:"opf:event" => "original-publication"}, @metadata["original-publication"] || Time.now.year
|
159
181
|
b.dc :date, {:"opf:event" => "epub-publication"}, @metadata["epub-publication"] || Time.now.year
|
182
|
+
|
183
|
+
|
184
|
+
if @sections.first.cover
|
185
|
+
b.meta :name => "cover", :content => @sections.first.cover
|
186
|
+
end
|
160
187
|
end
|
161
188
|
|
162
189
|
# <manifest>
|
@@ -165,22 +192,22 @@ module EpubForge
|
|
165
192
|
b.item :id => "ncx", :href => "toc.ncx", :"media-type" => "application/x-dtbncx+xml"
|
166
193
|
|
167
194
|
@sections.each_with_index do |section, i|
|
168
|
-
b.item :id => section.link, :href => section.link, :"media-type" => section.media_type
|
195
|
+
b.item :id => section.link.basename, :href => section.link.relative_path_from("/OEBPS"), :"media-type" => section.media_type
|
169
196
|
end
|
170
197
|
|
171
198
|
@images.each do |image|
|
172
|
-
b.item :id => image.
|
199
|
+
b.item :id => image.filename.basename, :href => image.link.relative_path_from("/OEBPS"), :"media-type" => image.media_type
|
173
200
|
end
|
174
201
|
|
175
202
|
@stylesheets.each do |sheet|
|
176
|
-
b.item :id => sheet.name, :href => sheet.link, :"media-type" => sheet.media_type
|
203
|
+
b.item :id => sheet.name, :href => sheet.link.relative_path_from("/OEBPS"), :"media-type" => sheet.media_type
|
177
204
|
end
|
178
205
|
end
|
179
206
|
|
180
207
|
# <spine toc="ncx">
|
181
208
|
b.spine :toc => "ncx" do
|
182
|
-
@sections.
|
183
|
-
b.itemref :idref =>
|
209
|
+
@sections.each do |section|
|
210
|
+
b.itemref :idref => section.dest_filename
|
184
211
|
end
|
185
212
|
end
|
186
213
|
|
@@ -196,7 +223,7 @@ module EpubForge
|
|
196
223
|
|
197
224
|
b.target!.to_s
|
198
225
|
end
|
199
|
-
|
226
|
+
|
200
227
|
# zips up contents
|
201
228
|
def build
|
202
229
|
Utils::DirectoryBuilder.create( @scratch_dir ) do |build|
|
@@ -212,8 +239,10 @@ module EpubForge
|
|
212
239
|
build.file( "content.opf", content_opf )
|
213
240
|
|
214
241
|
build.dir( "Text" ) do
|
215
|
-
@sections.
|
216
|
-
build.file(
|
242
|
+
@sections.each do |section|
|
243
|
+
build.file( section.dest_filename,
|
244
|
+
section.is_a?( Assets::XHTML ) ? section.html : wrap_page( section.html )
|
245
|
+
)
|
217
246
|
end
|
218
247
|
end
|
219
248
|
|
@@ -245,7 +274,7 @@ module EpubForge
|
|
245
274
|
end
|
246
275
|
|
247
276
|
protected
|
248
|
-
def wrap_page content
|
277
|
+
def wrap_page content = ""
|
249
278
|
b = XmlBuilder::XmlMarkup.new( :indent => 2)
|
250
279
|
b.instruct! :xml, :encoding => "utf-8", :standalone => "no"
|
251
280
|
b.declare! :DOCTYPE, :html, :PUBLIC, "-//W3C//DTD XHTML 1.1//EN", "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"
|
@@ -254,7 +283,7 @@ module EpubForge
|
|
254
283
|
b.head do
|
255
284
|
b.title( @metadata["name"] )
|
256
285
|
for sheet in @stylesheets
|
257
|
-
b.link :href => sheet.link, :media => "screen", :rel => "stylesheet", :type => "text/css"
|
286
|
+
b.link :href => sheet.link.relative_path_from("/OEBPS/Text"), :media => "screen", :rel => "stylesheet", :type => "text/css"
|
258
287
|
end
|
259
288
|
end
|
260
289
|
|
data/lib/epubforge.rb
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
# require 'singleton'
|
5
5
|
# require 'builder'
|
6
6
|
require 'thor'
|
7
|
+
require 'optparse'
|
7
8
|
require 'xdg' # keep configuration files in sane places
|
8
9
|
require 'debugger'
|
9
10
|
require 'erb'
|
@@ -15,7 +16,6 @@ require 'net/http'
|
|
15
16
|
require 'open-uri' # needed by Utils::Downloader
|
16
17
|
require 'yaml'
|
17
18
|
require 'rbconfig'
|
18
|
-
# require 'configurator'
|
19
19
|
require 'fun_with_files'
|
20
20
|
require 'fun_with_configurations'
|
21
21
|
|
@@ -90,6 +90,7 @@ require_relative 'epub/assets/markdown'
|
|
90
90
|
require_relative 'epub/assets/textile'
|
91
91
|
require_relative 'epub/assets/image'
|
92
92
|
require_relative 'epub/assets/stylesheet'
|
93
|
+
require_relative 'epub/assets/xhtml'
|
93
94
|
require_relative 'project/project'
|
94
95
|
|
95
96
|
puts "Requirements loaded" if debugging?
|
data/lib/utils/class_loader.rb
CHANGED
data/lib/utils/file_orderer.rb
CHANGED
@@ -5,7 +5,7 @@ module EpubForge
|
|
5
5
|
# by matching the filenames against one regex after another. Allows you to say,
|
6
6
|
# "I want the title page, the foreward, then all the chapters, then all the appendixes, then the afterword."
|
7
7
|
# Ex: FileOrderer( ["title_page", "forward", "chapter-.*", "afterword", "appendix.*" ).reorder( pages )
|
8
|
-
# Only compares the basename minus extension. Files should come from the same directory
|
8
|
+
# Only compares the basename minus extension. Files should come from the same directory. cover.extension always comes first.
|
9
9
|
class FileOrderer
|
10
10
|
def initialize( matchers )
|
11
11
|
@matchers = matchers.map do |m|
|
@@ -17,26 +17,26 @@ module EpubForge
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
@matchers.unshift( /^cover$/ )
|
20
21
|
@matchers.push( /^.*$/ )
|
21
22
|
end
|
22
23
|
|
23
24
|
def reorder( files )
|
24
25
|
files = files.map(&:fwf_filepath)
|
25
26
|
|
26
|
-
files.sort_by!{ |f|
|
27
|
-
f.basename_no_ext.to_s
|
28
|
-
}
|
29
|
-
|
30
|
-
|
31
27
|
ordered_files = @matchers.inject( [] ) do |collector, matcher|
|
32
28
|
matched_files = files.select do |f|
|
33
29
|
name = f.basename_no_ext.to_s
|
34
30
|
matcher.match( name )
|
35
31
|
end
|
36
|
-
|
37
|
-
|
32
|
+
|
33
|
+
matched_files.sort_by! do |filename|
|
34
|
+
filename.basename_no_ext.to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
collector += matched_files.sort
|
38
38
|
files -= matched_files
|
39
|
-
|
39
|
+
|
40
40
|
collector
|
41
41
|
end
|
42
42
|
end
|
data/lib/utils/file_path.rb
CHANGED
@@ -129,7 +129,7 @@ module EpubForge
|
|
129
129
|
self.basename.to_s.split(".").last || ""
|
130
130
|
end
|
131
131
|
|
132
|
-
def
|
132
|
+
def relative_path_from( ancestor_dir )
|
133
133
|
depth = ancestor_dir.to_s.split(File::SEPARATOR).length
|
134
134
|
relative_path = self.to_s.split(File::SEPARATOR)
|
135
135
|
relative_path[(depth)..-1].join(File::SEPARATOR).fwf_filepath
|
@@ -74,7 +74,7 @@ module EpubForge
|
|
74
74
|
def translate( filename, opts = "" )
|
75
75
|
return false unless can_do_job?( filename )
|
76
76
|
|
77
|
-
result =
|
77
|
+
result = ""
|
78
78
|
if @custom_proc
|
79
79
|
result += @custom_proc.call( filename, *opts )
|
80
80
|
elsif @cmd
|
@@ -88,6 +88,7 @@ module EpubForge
|
|
88
88
|
return false
|
89
89
|
end
|
90
90
|
|
91
|
+
result += "\n\n<!-- generated from #{@format} by htmlizer #{@name} -->\n"
|
91
92
|
result
|
92
93
|
end
|
93
94
|
|
data/lib/utils/htmlizer.rb
CHANGED
@@ -0,0 +1,13 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
2
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
3
|
+
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
4
|
+
|
5
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
6
|
+
<head>
|
7
|
+
<title></title>
|
8
|
+
</head>
|
9
|
+
|
10
|
+
<body>
|
11
|
+
<p><img class="cover" alt="The Improbable Rise of Singularity Girl, by Bryce Anderson" src="../Images/cover.jpg" /></p>
|
12
|
+
</body>
|
13
|
+
</html>
|
Binary file
|
@@ -42,7 +42,7 @@ FunWith::Configurations::Config.new do
|
|
42
42
|
# chapter_summary that comes after, you might want to define the matcher more
|
43
43
|
# specifically, for example 'chapter-\d+' (chapter followed by dash followed by any number of numbers).
|
44
44
|
#
|
45
|
-
"chapter
|
45
|
+
"chapter-.*",
|
46
46
|
"afterword"
|
47
47
|
]
|
48
48
|
|
data/test/test_epubforge.rb
CHANGED
@@ -7,7 +7,7 @@ class TestEpubforge < Test::Unit::TestCase #
|
|
7
7
|
printout = EpubForge.collect_stdout do
|
8
8
|
EpubForge::Action::Runner.new.exec # empty args, should append --help
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
assert_match /\( wc \| count \)/, printout
|
12
12
|
assert_match /epubforge \[action\] \[folder\]/, printout
|
13
13
|
end
|
@@ -27,10 +27,10 @@ class TestEpubforge < Test::Unit::TestCase #
|
|
27
27
|
should "successfully count ALL THE WORDS!" do
|
28
28
|
create_project do
|
29
29
|
EpubForge.collect_stdout do
|
30
|
-
report = EpubForge::Action::Runner.new.exec( "wc", @project_dir )
|
30
|
+
report = EpubForge::Action::Runner.new.exec( "wc", @project_dir ).execution_returned
|
31
31
|
assert_kind_of Hash, report
|
32
|
-
assert_equal
|
33
|
-
assert_equal
|
32
|
+
assert_equal 119, report["Book"]
|
33
|
+
assert_equal 126, report["Today"]
|
34
34
|
assert @project_dir.join( EpubForge::Project::SETTINGS_FOLDER, EpubForge::Action::WordCount::WORD_COUNT_FILE ).exist?
|
35
35
|
end
|
36
36
|
end
|
@@ -39,7 +39,9 @@ class TestEpubforge < Test::Unit::TestCase #
|
|
39
39
|
should "fail to count words when no project is given and cwd is not a project" do
|
40
40
|
create_project do
|
41
41
|
printout = EpubForge.collect_stdout do
|
42
|
-
|
42
|
+
run_description = EpubForge::Action::Runner.new.exec( "wc" )
|
43
|
+
assert_equal nil, run_description.execution_returned
|
44
|
+
assert_equal false, run_description.success?
|
43
45
|
end
|
44
46
|
|
45
47
|
assert_match /Error\(s\) trying to complete the requested action/, printout
|
@@ -74,8 +76,8 @@ class TestEpubforge < Test::Unit::TestCase #
|
|
74
76
|
end
|
75
77
|
|
76
78
|
d.join("Text") do |d|
|
77
|
-
d.join( "
|
78
|
-
assert section.file
|
79
|
+
d.join( "afterword.xhtml" ) do |section|
|
80
|
+
assert section.file?, "file should exist: chapter-0002.xhtml"
|
79
81
|
section_text = section.read
|
80
82
|
assert_match /DOCTYPE/, section_text
|
81
83
|
assert_match /<title>#{@book_title}<\/title>/, section_text
|
@@ -90,7 +92,7 @@ class TestEpubforge < Test::Unit::TestCase #
|
|
90
92
|
d.join( "content.opf" ) do |content|
|
91
93
|
content_text = content.read
|
92
94
|
assert_match /<dc:title>#{@book_title}<\/dc:title>/, content_text
|
93
|
-
assert_match /Text\/
|
95
|
+
assert_match /Text\/chapter-0003/, content_text
|
94
96
|
end
|
95
97
|
|
96
98
|
d.join( "toc.ncx" ) do |toc|
|
@@ -128,7 +130,6 @@ class TestEpubforge < Test::Unit::TestCase #
|
|
128
130
|
|
129
131
|
assert @project_dir.directory?, "Project directory doesn't exist. Cannot proceed."
|
130
132
|
|
131
|
-
|
132
133
|
@book_title = fill_in_project_options[:answers][:title]
|
133
134
|
@chapter_count = fill_in_project_options[:answers][:chapter_count].to_i
|
134
135
|
@ebook_file = @project_dir.join( @book_title.epf_underscorize + ".epub" )
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: epubforge
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
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-
|
12
|
+
date: 2013-05-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: xdg
|
@@ -223,6 +223,7 @@ files:
|
|
223
223
|
- ./config/actions/help.rb
|
224
224
|
- ./config/actions/init.rb
|
225
225
|
- ./config/actions/kindle.rb
|
226
|
+
- ./config/actions/mobify.rb
|
226
227
|
- ./config/actions/notes_to_epub.rb
|
227
228
|
- ./config/actions/notes_to_kindle.rb
|
228
229
|
- ./config/actions/word_count.rb
|
@@ -248,6 +249,7 @@ files:
|
|
248
249
|
- ./lib/epub/assets/page.rb
|
249
250
|
- ./lib/epub/assets/stylesheet.rb
|
250
251
|
- ./lib/epub/assets/textile.rb
|
252
|
+
- ./lib/epub/assets/xhtml.rb
|
251
253
|
- ./lib/epub/builder.rb
|
252
254
|
- ./lib/epub/packager.rb
|
253
255
|
- ./lib/epubforge.rb
|
@@ -268,11 +270,13 @@ files:
|
|
268
270
|
- ./lib/utils/template_evaluator.rb
|
269
271
|
- ./templates/default/book/afterword.markdown.template
|
270
272
|
- ./templates/default/book/chapter-%i%.markdown.sequence
|
273
|
+
- ./templates/default/book/cover.xhtml.template
|
271
274
|
- ./templates/default/book/foreword.markdown.template
|
272
275
|
- ./templates/default/book/images/cover.png
|
273
276
|
- ./templates/default/book/stylesheets/stylesheet.css.template
|
274
277
|
- ./templates/default/book/title_page.markdown.template
|
275
278
|
- ./templates/default/notes/character.named.markdown.template
|
279
|
+
- ./templates/default/notes/images/cover.png
|
276
280
|
- ./templates/default/notes/stylesheets/stylesheet.css.template
|
277
281
|
- ./templates/default/payload.rb
|
278
282
|
- ./templates/default/settings/actions/local_action.rb.example
|
@@ -311,7 +315,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
311
315
|
version: '0'
|
312
316
|
segments:
|
313
317
|
- 0
|
314
|
-
hash:
|
318
|
+
hash: 243230996870064853
|
315
319
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
316
320
|
none: false
|
317
321
|
requirements:
|