epubforge 0.0.5
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/Gemfile +26 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +26 -0
- data/Rakefile +71 -0
- data/VERSION +1 -0
- data/bin/epubforge +10 -0
- data/config/actions/book_to_epub.rb +20 -0
- data/config/actions/generate.rb +24 -0
- data/config/actions/generate_chapter.rb +26 -0
- data/config/actions/git_backup.rb +23 -0
- data/config/actions/gitify.rb +72 -0
- data/config/actions/globals.rb +77 -0
- data/config/actions/help.rb +21 -0
- data/config/actions/init.rb +137 -0
- data/config/actions/kindle.rb +68 -0
- data/config/actions/notes_to_epub.rb +20 -0
- data/config/actions/notes_to_kindle.rb +17 -0
- data/config/actions/word_count.rb +126 -0
- data/config/actions/wrap_scene_notes_in_hidden_div.rb +118 -0
- data/config/htmlizers.rb +62 -0
- data/lib/action/actions_lookup.rb +41 -0
- data/lib/action/cli_command.rb +72 -0
- data/lib/action/cli_sequence.rb +55 -0
- data/lib/action/file_transformer.rb +59 -0
- data/lib/action/run_description.rb +24 -0
- data/lib/action/runner.rb +122 -0
- data/lib/action/thor_action.rb +149 -0
- data/lib/core_extensions/array.rb +5 -0
- data/lib/core_extensions/kernel.rb +42 -0
- data/lib/core_extensions/nil_class.rb +5 -0
- data/lib/core_extensions/object.rb +5 -0
- data/lib/core_extensions/string.rb +37 -0
- data/lib/custom_helpers.rb +60 -0
- data/lib/epub/assets/asset.rb +11 -0
- data/lib/epub/assets/html.rb +8 -0
- data/lib/epub/assets/image.rb +18 -0
- data/lib/epub/assets/markdown.rb +8 -0
- data/lib/epub/assets/page.rb +32 -0
- data/lib/epub/assets/stylesheet.rb +22 -0
- data/lib/epub/assets/textile.rb +8 -0
- data/lib/epub/builder.rb +270 -0
- data/lib/epub/packager.rb +16 -0
- data/lib/epubforge.rb +97 -0
- data/lib/errors.rb +8 -0
- data/lib/project/project.rb +65 -0
- data/lib/utils/action_loader.rb +7 -0
- data/lib/utils/class_loader.rb +83 -0
- data/lib/utils/directory_builder.rb +181 -0
- data/lib/utils/downloader.rb +58 -0
- data/lib/utils/file_orderer.rb +45 -0
- data/lib/utils/file_path.rb +152 -0
- data/lib/utils/html_translator.rb +99 -0
- data/lib/utils/html_translator_queue.rb +70 -0
- data/lib/utils/htmlizer.rb +92 -0
- data/lib/utils/misc.rb +20 -0
- data/lib/utils/root_path.rb +20 -0
- data/lib/utils/settings.rb +146 -0
- data/lib/utils/template_evaluator.rb +20 -0
- data/templates/default/book/afterword.markdown.template +4 -0
- data/templates/default/book/chapter-%i%.markdown.sequence +4 -0
- data/templates/default/book/foreword.markdown.template +6 -0
- data/templates/default/book/images/cover.png +0 -0
- data/templates/default/book/stylesheets/stylesheet.css.template +2 -0
- data/templates/default/book/title_page.markdown.template +4 -0
- data/templates/default/notes/character.named.markdown.template +4 -0
- data/templates/default/notes/stylesheets/stylesheet.css.template +2 -0
- data/templates/default/payload.rb +65 -0
- data/templates/default/settings/actions/local_action.rb.example +14 -0
- data/templates/default/settings/config.rb.form +55 -0
- data/templates/default/settings/htmlizers.rb +0 -0
- data/templates/default/settings/wordcount.template +6 -0
- data/test/helper.rb +22 -0
- data/test/misc/config.rb +7 -0
- data/test/sample_text/sample.markdown +30 -0
- data/test/sample_text/sample.textile +24 -0
- data/test/test_custom_helpers.rb +22 -0
- data/test/test_directory_builder.rb +141 -0
- data/test/test_epf_root.rb +9 -0
- data/test/test_epubforge.rb +164 -0
- data/test/test_htmlizers.rb +24 -0
- data/test/test_runner.rb +15 -0
- data/test/test_utils.rb +39 -0
- metadata +328 -0
@@ -0,0 +1,149 @@
|
|
1
|
+
module EpubForge
|
2
|
+
module Action
|
3
|
+
module SharedActionInterface
|
4
|
+
def description( str = nil )
|
5
|
+
@description = str if str
|
6
|
+
@description
|
7
|
+
end
|
8
|
+
|
9
|
+
def keywords( *args )
|
10
|
+
if args.epf_blank?
|
11
|
+
@keywords ||= []
|
12
|
+
else
|
13
|
+
@keywords = args.map(&:to_s)
|
14
|
+
end
|
15
|
+
|
16
|
+
@keywords
|
17
|
+
end
|
18
|
+
|
19
|
+
def usage( str = nil )
|
20
|
+
@usage = str if str
|
21
|
+
@usage
|
22
|
+
end
|
23
|
+
|
24
|
+
def project_required?
|
25
|
+
@project_required = true if @project_required.nil?
|
26
|
+
@project_required
|
27
|
+
end
|
28
|
+
|
29
|
+
# Most actions require -- nay, demand! -- a project to act upon.
|
30
|
+
# Add the line 'project_not_required' to the class definition
|
31
|
+
# to keep it from failing out if it can't find an existing project.
|
32
|
+
# Used for things like initializing new projects, or... my imagination
|
33
|
+
# fails me.
|
34
|
+
def project_not_required
|
35
|
+
@project_required = false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class ThorAction < Thor
|
40
|
+
include Thor::Actions
|
41
|
+
extend SharedActionInterface
|
42
|
+
|
43
|
+
|
44
|
+
CLEAR = Thor::Shell::Color::CLEAR
|
45
|
+
RED = Thor::Shell::Color::RED
|
46
|
+
BLUE = Thor::Shell::Color::BLUE
|
47
|
+
YELLOW = Thor::Shell::Color::YELLOW
|
48
|
+
GREEN = Thor::Shell::Color::GREEN
|
49
|
+
MAGENTA = Thor::Shell::Color::MAGENTA
|
50
|
+
ON_YELLOW = Thor::Shell::Color::ON_YELLOW
|
51
|
+
ON_BLUE = Thor::Shell::Color::ON_BLUE
|
52
|
+
|
53
|
+
|
54
|
+
protected
|
55
|
+
def say_error( statement )
|
56
|
+
say( "ERROR : #{statement}", RED + ON_BLUE )
|
57
|
+
end
|
58
|
+
|
59
|
+
def say_instruction( statement )
|
60
|
+
say( statement, YELLOW )
|
61
|
+
end
|
62
|
+
|
63
|
+
def say_all_is_well( statement )
|
64
|
+
say( statement, GREEN )
|
65
|
+
end
|
66
|
+
|
67
|
+
def say_in_warning( statement )
|
68
|
+
warn( statement, RED )
|
69
|
+
end
|
70
|
+
|
71
|
+
def say_subtly( statement )
|
72
|
+
say( statement, MAGENTA )
|
73
|
+
end
|
74
|
+
|
75
|
+
def yes_prettily?( statement )
|
76
|
+
yes?( statement, BLUE )
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
|
81
|
+
# choices = Array of Arrays(length:2) or Strings. Can be intermingled freely.
|
82
|
+
# when the user selects a string, returns the string. For the array,
|
83
|
+
# the user sees the first item, and the programmer gets back the last item
|
84
|
+
def ask_from_menu( statement, choices )
|
85
|
+
choices.map! do |choice|
|
86
|
+
choice.is_a?(String) ? [choice] : choice # I'm being too clever by half here. .first/.last still works.
|
87
|
+
end
|
88
|
+
|
89
|
+
choice_text = ""
|
90
|
+
choices.each_with_index{ |choice,i|
|
91
|
+
choice_text << "\t\t#{i}) #{choice.first}\n"
|
92
|
+
}
|
93
|
+
|
94
|
+
selection = ask( "#{statement}\n\tChoices:\n#{choice_text}>>> ", BLUE )
|
95
|
+
choices[selection.to_i].last
|
96
|
+
end
|
97
|
+
|
98
|
+
def ask_prettily( statement )
|
99
|
+
ask( statement, BLUE )
|
100
|
+
end
|
101
|
+
|
102
|
+
# hope this doesn't break anything. Sure enough, it broke a lot of things.
|
103
|
+
# def destination_root=( root )
|
104
|
+
# @destination_stack ||= []
|
105
|
+
# @destination_stack << (root ? root.fwf_filepath.expand : '')
|
106
|
+
# end
|
107
|
+
|
108
|
+
# Instead, use these instead of destination_root. Thor gets strings instead of
|
109
|
+
# filepaths, like it wants, and I get filepaths instead of strings, like I want.
|
110
|
+
def destination_root_filepath
|
111
|
+
self.destination_root.fwf_filepath
|
112
|
+
end
|
113
|
+
|
114
|
+
def destination_root_filepath=(root)
|
115
|
+
self.destination_root = root.to_s
|
116
|
+
end
|
117
|
+
|
118
|
+
def executable_installed?( name )
|
119
|
+
name = name.to_sym
|
120
|
+
|
121
|
+
if @executables.nil?
|
122
|
+
@executables = {}
|
123
|
+
for exe, path in (EpubForge.config[:exe_paths] || {})
|
124
|
+
@executables[exe] = path.fwf_filepath
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
@executables[name] ||= begin
|
129
|
+
_which = `which #{name}`.strip
|
130
|
+
(_which.length == 0) ? false : _which.fwf_filepath
|
131
|
+
end
|
132
|
+
|
133
|
+
@executables[name]
|
134
|
+
end
|
135
|
+
|
136
|
+
def git_installed?
|
137
|
+
executable_installed?('git')
|
138
|
+
end
|
139
|
+
|
140
|
+
def ebook_convert_installed?
|
141
|
+
executable_installed?('ebook-convert')
|
142
|
+
end
|
143
|
+
|
144
|
+
def project_already_gitted?
|
145
|
+
@project.target_dir.join( ".git" ).directory?
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,42 @@
|
|
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
|
+
# yields an alternate reality block where instance methods
|
23
|
+
# are different from what they were. At the end of the block
|
24
|
+
# it resets the initial values of the instance variables.
|
25
|
+
def with_locals locals = {}, &block
|
26
|
+
old_local_vars = {}
|
27
|
+
|
28
|
+
for k, v in locals
|
29
|
+
var = :"@#{k}"
|
30
|
+
old_local_vars[k] = instance_variable_get(var)
|
31
|
+
instance_variable_set( var, v )
|
32
|
+
end
|
33
|
+
|
34
|
+
yield
|
35
|
+
ensure # make all as it once was
|
36
|
+
for k, v in old_local_vars
|
37
|
+
var = :"@#{k}"
|
38
|
+
instance_variable_set( var, v )
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class String
|
2
|
+
TITLE_WORDS_NOT_CAPITALIZED = %W(a an in the for and nor but or yet so also)
|
3
|
+
def epf_blank?
|
4
|
+
self.strip.length == 0
|
5
|
+
end
|
6
|
+
|
7
|
+
def epf_camelize
|
8
|
+
gsub(/(?:^|_)(.)/) { $1.upcase }
|
9
|
+
end
|
10
|
+
|
11
|
+
# TODO: Need comprehensive list of characters to be protected.
|
12
|
+
def epf_backhashed_filename
|
13
|
+
self.gsub(" ", "\\ ")
|
14
|
+
end
|
15
|
+
|
16
|
+
def epf_underscorize
|
17
|
+
self.downcase.gsub(/\s+/,"_").gsub(/[\W]/,"")
|
18
|
+
end
|
19
|
+
|
20
|
+
# def fwf_filepath
|
21
|
+
# EpubForge::FunWith::Files::FilePath.new(self)
|
22
|
+
# end
|
23
|
+
|
24
|
+
def to_pathname
|
25
|
+
Pathname.new( self )
|
26
|
+
end
|
27
|
+
|
28
|
+
def epf_deunderscorize_as_title
|
29
|
+
words = self.split("_")
|
30
|
+
|
31
|
+
words = [words[0].capitalize] + words[1..-1].map{|w|
|
32
|
+
TITLE_WORDS_NOT_CAPITALIZED.include?(w) ? w : w.capitalize
|
33
|
+
}
|
34
|
+
|
35
|
+
words.join(" ")
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module EpubForge
|
2
|
+
module CustomHelpers
|
3
|
+
def ask question, opts = {}
|
4
|
+
opts[:menu] ||= [["Y", "Yes"], ["N", "No"]]
|
5
|
+
|
6
|
+
answer = nil
|
7
|
+
|
8
|
+
while answer.nil?
|
9
|
+
menu_string = opts[:menu].map{ |li| "#{li[0]}):\t#{li[1]}"}.join("\n\t")
|
10
|
+
puts "#{question} :\n\t#{ menu_string }"
|
11
|
+
line = Readline.readline(">> ",true).strip.upcase
|
12
|
+
|
13
|
+
opts[:menu].each{ |li|
|
14
|
+
if li[0].upcase == line.to_s
|
15
|
+
answer = li
|
16
|
+
end
|
17
|
+
}
|
18
|
+
|
19
|
+
puts "I don't understand that response" if answer.nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
if opts[:return_value]
|
23
|
+
answer[1]
|
24
|
+
else
|
25
|
+
answer[0].upcase
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def collect_stdout( dest = StringIO.new, &block )
|
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
|
+
# end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
EpubForge.extend( EpubForge::CustomHelpers )
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module EpubForge
|
2
|
+
module Epub
|
3
|
+
module Assets
|
4
|
+
class Image < Asset
|
5
|
+
attr_reader :ext, :filename, :name
|
6
|
+
def initialize( filename, options = {} )
|
7
|
+
@filename = filename.fwf_filepath
|
8
|
+
@name = @filename.basename.to_s.split(".")[0..-2].join(".")
|
9
|
+
@ext = @filename.extname.gsub( /^\./, "" )
|
10
|
+
end
|
11
|
+
|
12
|
+
def link
|
13
|
+
IMAGES_DIR.join( @name )
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module EpubForge
|
2
|
+
module Epub
|
3
|
+
module Assets
|
4
|
+
class Page < Asset
|
5
|
+
attr_reader :html, :original_file, :title, :project, :media_type, :dest_extension
|
6
|
+
attr_accessor :section_id, :section_number
|
7
|
+
|
8
|
+
def initialize file, metadata, project
|
9
|
+
raise "NIL" if project.nil?
|
10
|
+
|
11
|
+
@metadata = metadata
|
12
|
+
@project = project
|
13
|
+
@original_file = file
|
14
|
+
@dest_extension = "xhtml"
|
15
|
+
|
16
|
+
@html = Utils::Htmlizer.instance.translate( file )
|
17
|
+
@title = File.basename( file ).split(".")[0..-2].map(&:capitalize).join(" : ")
|
18
|
+
@content = ""
|
19
|
+
puts "Initialized #{file} with title [#{@title}]"
|
20
|
+
end
|
21
|
+
|
22
|
+
def link
|
23
|
+
TEXT_DIR.join( "section#{ sprintf("%04i", @section_number) }.#{@dest_extension}" )
|
24
|
+
end
|
25
|
+
|
26
|
+
def media_type
|
27
|
+
MEDIA_TYPES[@dest_extension]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module EpubForge
|
2
|
+
module Epub
|
3
|
+
module Assets
|
4
|
+
class Stylesheet < Asset
|
5
|
+
attr_accessor :filename, :name, :contents
|
6
|
+
def initialize( filename )
|
7
|
+
@filename = filename.fwf_filepath
|
8
|
+
@name = @filename.basename
|
9
|
+
@contents = @filename.read
|
10
|
+
end
|
11
|
+
|
12
|
+
def link
|
13
|
+
STYLE_DIR.join( @name )
|
14
|
+
end
|
15
|
+
|
16
|
+
def media_type
|
17
|
+
MEDIA_TYPES["css"]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|