Skip to content
This repository has been archived by the owner on May 11, 2022. It is now read-only.

Commit

Permalink
improvements for allowing gem to be used as a lib
Browse files Browse the repository at this point in the history
less reliance on actual file structure, more options for using the
hooks in Epub directly and feeding it templates from memory (as strings)
  • Loading branch information
jlapier committed Jan 22, 2012
1 parent 322f0f2 commit 3368e13
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 50 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ gem 'liquid'
gem 'uuid'
gem 'linguistics'
gem 'zipruby'
gem 'rdoc'


# Add dependencies to develop your gem here.
Expand Down
28 changes: 17 additions & 11 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
GEM
remote: http://rubygems.org/
specs:
RedCloth (4.2.7)
diff-lcs (1.1.2)
RedCloth (4.2.9)
diff-lcs (1.1.3)
git (1.2.5)
jeweler (1.5.2)
bundler (~> 1.0.0)
git (>= 1.2.5)
rake
linguistics (1.0.8)
liquid (2.2.2)
macaddr (1.0.0)
rake (0.9.2)
rcov (0.9.9)
json (1.6.5)
linguistics (1.0.9)
liquid (2.3.0)
macaddr (1.5.0)
systemu (>= 2.4.0)
rake (0.9.2.2)
rcov (1.0.0)
rdoc (3.12)
json (~> 1.4)
rspec (2.2.0)
rspec-core (~> 2.2)
rspec-expectations (~> 2.2)
rspec-mocks (~> 2.2)
rspec-core (2.6.4)
rspec-expectations (2.6.0)
rspec-core (2.8.0)
rspec-expectations (2.8.0)
diff-lcs (~> 1.1.2)
rspec-mocks (2.6.0)
uuid (2.3.2)
rspec-mocks (2.8.0)
systemu (2.4.2)
uuid (2.3.4)
macaddr (~> 1.0)
zipruby (0.3.6)

Expand All @@ -36,6 +41,7 @@ DEPENDENCIES
liquid
rake
rcov
rdoc
rspec (~> 2.2.0)
uuid
zipruby
4 changes: 2 additions & 2 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ end

task :default => :spec

require 'rake/rdoctask'
Rake::RDocTask.new do |rdoc|
require 'rdoc/task'
RDoc::Task.new do |rdoc|
version = File.exist?('VERSION') ? File.read('VERSION') : ""

rdoc.rdoc_dir = 'rdoc'
Expand Down
9 changes: 5 additions & 4 deletions bin/epubbery
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,17 @@ elsif File.exist?('config.yml')

@book = Book.new @config[:book_title], @config[:author]
@book.chapters = Epub.read_chapters(@config[:chapter_glob])

# @epub.make_skeleton Dir.getwd, @epub_folder, @config[:default_template]
#@epub.write_templates(@book)

# # uncomment to actually write temp rendered html files
# @epub.make_skeleton Dir.getwd, @epub_folder, @config[:default_template]
# @epub.write_templates(@book)

FileUtils.rm @config[:file_name] if File.exists?(@config[:file_name])

puts "\nGenerating #{@config[:file_name]}"
FileUtils.cp File.join(@gem_dir, 'lib', 'base.epub'), @config[:file_name]

@epub.read_templates(Dir.getwd, @config[:default_template])
@epub.load_file_templates(Dir.getwd, @config[:default_template])
@epub.create_zip(@book, @config[:file_name])

puts "\nRunning epubcheck..."
Expand Down
132 changes: 99 additions & 33 deletions lib/epub.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
# making directories and moving files and whatnot
class Epub
class << self
# kind of an orphaned method that just reads in chapters from text files and returns chapter objects
# kind of an orphaned method that just reads in chapters from text files
# and returns chapter objects
def read_chapters(file_glob)
file_glob = File.expand_path(file_glob)
puts "Reading files: #{file_glob} (#{Dir[file_glob].size} files found)"
Expand All @@ -22,6 +23,9 @@ def read_chapters(file_glob)
end
end

# only useful for setting up the generation of actual HTML files
# not used in the current version of the gem (HTML is generated in memory,
# not written to files)
def make_skeleton(base_dir, epub_folder, default_template = 'chapter')
default_template ||= 'chapter'
@epub_folder = epub_folder
Expand All @@ -34,56 +38,115 @@ def make_skeleton(base_dir, epub_folder, default_template = 'chapter')
FileUtils.mkdir_p @target_meta_dir
FileUtils.mkdir_p @target_oebps_dir

FileUtils.cp File.join(@source_templates_dir, 'META-INF', 'container.xml'), @target_meta_dir
FileUtils.cp File.join(@source_templates_dir, 'META-INF', 'container.xml'),
@target_meta_dir

# TODO - somehow detect these "asset" folders and files -
# for now they are these defaults: css, images, fonts
FileUtils.cp Dir[File.join(@source_templates_dir, 'OEBPS', '*.css')], @target_oebps_dir
FileUtils.cp_r File.join(@source_templates_dir, 'OEBPS', 'images'), @target_oebps_dir
FileUtils.cp_r File.join(@source_templates_dir, 'OEBPS', 'fonts'), @target_oebps_dir

read_templates(base_dir, default_template)
FileUtils.cp Dir[File.join(@source_templates_dir, 'OEBPS', '*.css')],
@target_oebps_dir
FileUtils.cp_r File.join(@source_templates_dir, 'OEBPS', 'images'),
@target_oebps_dir
FileUtils.cp_r File.join(@source_templates_dir, 'OEBPS', 'fonts'),
@target_oebps_dir

load_file_templates(base_dir, default_template)
end

def read_templates(base_dir, default_template = 'chapter')
default_template ||= 'chapter'
@source_templates_dir = File.join(base_dir, 'templates')
# load liquid templates from files in the templates directory
def load_file_templates(base_dir, default_template = 'chapter')
@source_templates_dir ||= File.join(base_dir, 'templates')

# liquid templates for rest of files
@default_liq_template = Liquid::Template.parse(File.read(File.join(@source_templates_dir, 'OEBPS', "#{default_template.gsub(' ', '_')}.html.liquid" )))
@content_liq_template = Liquid::Template.parse(File.read(File.join(@source_templates_dir, 'OEBPS', 'content.opf.liquid' )))
@title_liq_template = Liquid::Template.parse(File.read(File.join(@source_templates_dir, 'OEBPS', 'title.html.liquid' )))
@toc_liq_template = Liquid::Template.parse(File.read(File.join(@source_templates_dir, 'OEBPS', 'toc.ncx.liquid' )))
@eob_liq_template = Liquid::Template.parse(File.read(File.join(@source_templates_dir, 'OEBPS', 'end_of_book.html.liquid')))
default = File.read(File.join(@source_templates_dir, 'OEBPS',
"#{default_template.gsub(' ', '_')}.html.liquid" ))
content = File.read(File.join(@source_templates_dir, 'OEBPS',
'content.opf.liquid'))
title = File.read(File.join(@source_templates_dir, 'OEBPS', 'title.html.liquid'))
toc = File.read(File.join(@source_templates_dir, 'OEBPS', 'toc.ncx.liquid'))
eob = File.read(File.join(@source_templates_dir, 'OEBPS',
'end_of_book.html.liquid'))

load_custom_templates(default, content, title, toc, eob)
end

# load liquid templates, manually (provide String objects from memory or db)
# default: default template for all chapters (html)
# content: template for content.opf (xml)
# title: title page (html)
# toc: table of contents (for toc.ncx, xml)
# eob: end of book page (html)
def load_custom_templates(default, content, title, toc, eob)
@default_liq_template = Liquid::Template.parse(default)
@content_liq_template = Liquid::Template.parse(content)
@title_liq_template = Liquid::Template.parse(title)
@toc_liq_template = Liquid::Template.parse(toc)
@eob_liq_template = Liquid::Template.parse(eob)
end

# finds css, images, fonts in templates directory
def find_asset_files
@css_files = Dir[File.join(@source_templates_dir, 'OEBPS', '*.css')].
map { |f| File.basename(f) }
@image_files = Dir[File.join(@source_templates_dir, 'OEBPS', 'images', '*')].
map { |f| File.basename(f) }
@font_files = Dir[File.join(@source_templates_dir, 'OEBPS', 'fonts', '*')].
map { |f| File.basename(f) }
end

def render_templates(book)
# provide arrays of each asset type (directory path not necessary)
def custom_asset_files(css_files, image_files, font_files)
@css_files = css_files
@image_files = image_files
@font_files = font_files
end

# returns a hash where the keys are file paths and the values are rendered templates
# provide extra templates in the form of a hash:
# { 'name' => 'liquid template string' }
def render_templates(book, extra_templates = nil)
unless extra_templates
# scan the source folder for html liquid templates
extra_templates = {}
Dir[File.join(@source_templates_dir, 'OEBPS', '*.html.liquid')].each do |f|
friendly_name = File.basename(f).gsub('_', ' ').gsub('.html.liquid', '')
extra_templates[friendly_name] = File.read(f)
end
end

rendered = {}
find_asset_files unless @css_files

book.chapters.each do |chapter|
template = @default_liq_template
if chapter.template
template = Liquid::Template.parse(File.read(File.join(@source_templates_dir, 'OEBPS', "#{chapter.template.gsub(' ', '_')}.html.liquid" )))
# if this chapter has a specific template AND we can find it, use it
if chapter.template and extra_templates[chapter.template.downcase]
template = Liquid::Template.parse(extra_templates[chapter.template.downcase])
end
html_output = template.render 'chapter' => chapter
puts "Rendering: OEBPS/#{chapter.file_name}"
rendered[File.join('OEBPS', chapter.file_name)] = html_output
end

puts "Rendering: OEBPS/content.opf"
rendered[File.join('OEBPS', 'content.opf')] = @content_liq_template.render('book' => book,
'css_files' => Dir[File.join(@source_templates_dir, 'OEBPS', '*.css')].map { |f| File.basename(f) },
'image_files' => Dir[File.join(@source_templates_dir, 'OEBPS', 'images', '*')].map { |f| File.basename(f) },
'font_files' => Dir[File.join(@source_templates_dir, 'OEBPS', 'fonts', '*')].map { |f| File.basename(f) } )
# content.opf template needs to know location of asset files
rendered[File.join('OEBPS', 'content.opf')] = @content_liq_template.render(
'book' => book,
'css_files' => @css_files,
'image_files' => @image_files,
'font_files' => @font_files )

puts "Rendering: OEBPS/title.html"
rendered[File.join('OEBPS', 'title.html')] = @title_liq_template.render('book' => book)
rendered[File.join('OEBPS', 'title.html')] = @title_liq_template.render(
'book' => book)

puts "Rendering: OEBPS/end_of_book.html"
rendered[File.join('OEBPS', 'end_of_book.html')] = @eob_liq_template.render('book' => book)
rendered[File.join('OEBPS', 'end_of_book.html')] = @eob_liq_template.render(
'book' => book)

puts "Rendering: OEBPS/toc.ncx"
rendered[File.join('OEBPS', 'toc.ncx')] = @toc_liq_template.render('book' => book)
rendered[File.join('OEBPS', 'toc.ncx')] = @toc_liq_template.render(
'book' => book)

rendered
end
Expand All @@ -96,18 +159,21 @@ def write_templates(book)
end
end

def create_zip(book, zipfile)
def create_zip(book, zipfile, asset_loc = nil, container_loc = nil)
asset_loc ||= File.join(@source_templates_dir, 'OEBPS')
container_loc ||= File.join(@source_templates_dir, 'META-INF', 'container.xml')
rendered_templates = render_templates(book)

Zip::Archive.open(zipfile) do |ar|
ar.add_file 'META-INF/container.xml', File.join(@source_templates_dir, 'META-INF', 'container.xml')
Dir[File.join(@source_templates_dir, 'OEBPS', '*.css')].each do |path|
ar.add_file("OEBPS/#{File.basename(path)}", path)
ar.add_file 'META-INF/container.xml', container_loc
@css_files.each do |f|
ar.add_file("OEBPS/#{f}", File.join(asset_loc, f))
end
Dir[File.join(@source_templates_dir, 'OEBPS', 'images', '*')].each do |path|
ar.add_file("OEBPS/images/#{File.basename(path)}", path)
@image_files.each do |f|
ar.add_file("OEBPS/images/#{f}", File.join(asset_loc, 'images', f))
end
Dir[File.join(@source_templates_dir, 'OEBPS', 'fonts', '*')].each do |path|
ar.add_file("OEBPS/fonts/#{File.basename(path)}", path)
@font_files.each do |f|
ar.add_file("OEBPS/fonts/#{f}", File.join(asset_loc, 'fonts', f))
end
rendered_templates.each do |filepath, text|
puts "Adding: #{filepath}"
Expand Down
14 changes: 14 additions & 0 deletions spec/epub_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
before(:all) do
@epub = Epub.new
@tmp_epub_folder = "test_epub_folder_safe_to_remove_will_be_deleted"
@tmp_epub_file = "test_zip_safe_to_remove.epub"
@base_dir = File.expand_path(File.dirname(__FILE__) + "/..")
@tmp_text_folder = "test_epub_folder_safe_to_remove_will_be_deleted2"
FileUtils.rm_rf File.join(@base_dir, @tmp_text_folder) if File.exists?(File.join(@base_dir, @tmp_text_folder))
Expand All @@ -25,6 +26,7 @@
FileUtils.rm_rf File.join(@base_dir, @tmp_epub_folder)
FileUtils.rm_rf File.join(@base_dir, @tmp_text_folder)
FileUtils.rm File.join(@base_dir, 'templates', 'OEBPS', 'delete_this_alternate.html.liquid')
FileUtils.rm File.join(@base_dir, @tmp_epub_file)
end

it "should make skeleton" do
Expand Down Expand Up @@ -63,4 +65,16 @@
File.exists?(File.join(@tmp_epub_folder, 'OEBPS', '2.html')).should == true
File.exists?(File.join(@tmp_epub_folder, 'OEBPS', 'end_of_book.html')).should == true
end

it "should create a zip file" do
@epub.make_skeleton @base_dir, @tmp_epub_folder
book = Book.new "Testy", "Jason", Date.new(2001)
book.chapters = Epub.read_chapters("#{File.join(@base_dir, @tmp_text_folder)}/*.txt")
@epub.write_templates book
blank_epub = File.join(@base_dir, 'lib', 'base.epub')
FileUtils.cp blank_epub, @tmp_epub_file
@epub.create_zip book, @tmp_epub_file
File.exists?(@tmp_epub_file)
File.size(blank_epub).should < File.size(@tmp_epub_file)
end
end

0 comments on commit 3368e13

Please sign in to comment.