epubbery 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +19 -0
  4. data/Gemfile.lock +38 -0
  5. data/LICENSE.txt +26 -0
  6. data/README.rdoc +41 -0
  7. data/Rakefile +55 -0
  8. data/VERSION +1 -0
  9. data/bin/epubbery +57 -0
  10. data/config_sample.yml +7 -0
  11. data/epubbery.gemspec +126 -0
  12. data/lib/book.rb +30 -0
  13. data/lib/chapter.rb +66 -0
  14. data/lib/epub_setup.rb +70 -0
  15. data/lib/epubbery.rb +16 -0
  16. data/spec/book_spec.rb +25 -0
  17. data/spec/chapter_spec.rb +65 -0
  18. data/spec/epub_setup_spec.rb +52 -0
  19. data/spec/spec_helper.rb +12 -0
  20. data/templates/META-INF/container.xml +7 -0
  21. data/templates/OEBPS/chapter.html.liquid +24 -0
  22. data/templates/OEBPS/content.opf.liquid +41 -0
  23. data/templates/OEBPS/end_of_book.html.liquid +33 -0
  24. data/templates/OEBPS/fonts/BergamoStd-Bold.otf +0 -0
  25. data/templates/OEBPS/fonts/BergamoStd-BoldItalic.otf +0 -0
  26. data/templates/OEBPS/fonts/BergamoStd-Italic.otf +0 -0
  27. data/templates/OEBPS/fonts/BergamoStd-Regular.otf +0 -0
  28. data/templates/OEBPS/fonts/OFLGoudyStM-Italic.otf +0 -0
  29. data/templates/OEBPS/fonts/OFLGoudyStM.otf +0 -0
  30. data/templates/OEBPS/fonts/licenses.txt +158 -0
  31. data/templates/OEBPS/fonts/texgyrepagella-bold.otf +0 -0
  32. data/templates/OEBPS/fonts/texgyrepagella-bolditalic.otf +0 -0
  33. data/templates/OEBPS/fonts/texgyrepagella-italic.otf +0 -0
  34. data/templates/OEBPS/fonts/texgyrepagella-regular.otf +0 -0
  35. data/templates/OEBPS/fonts/texgyretermes-bold.otf +0 -0
  36. data/templates/OEBPS/fonts/texgyretermes-bolditalic.otf +0 -0
  37. data/templates/OEBPS/fonts/texgyretermes-italic.otf +0 -0
  38. data/templates/OEBPS/fonts/texgyretermes-regular.otf +0 -0
  39. data/templates/OEBPS/fonts.css +127 -0
  40. data/templates/OEBPS/images/made_by_obf.jpg +0 -0
  41. data/templates/OEBPS/print.css +4 -0
  42. data/templates/OEBPS/stylesheet.css +82 -0
  43. data/templates/OEBPS/title.html.liquid +13 -0
  44. data/templates/OEBPS/toc.ncx.liquid +30 -0
  45. data/templates/mimetype +1 -0
  46. metadata +290 -0
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,19 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ gem 'RedCloth'
7
+ gem 'liquid'
8
+ gem 'uuid'
9
+ gem 'linguistics'
10
+
11
+
12
+ # Add dependencies to develop your gem here.
13
+ # Include everything needed to run rake, tests, features, etc.
14
+ group :development do
15
+ gem "rspec", "~> 2.2.0"
16
+ gem "bundler", "~> 1.0.0"
17
+ gem "jeweler", "~> 1.5.1"
18
+ gem "rcov", ">= 0"
19
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,38 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ RedCloth (4.2.3)
5
+ diff-lcs (1.1.2)
6
+ git (1.2.5)
7
+ jeweler (1.5.1)
8
+ bundler (~> 1.0.0)
9
+ git (>= 1.2.5)
10
+ rake
11
+ linguistics (1.0.8)
12
+ liquid (2.2.2)
13
+ macaddr (1.0.0)
14
+ rake (0.8.7)
15
+ rcov (0.9.9)
16
+ rspec (2.2.0)
17
+ rspec-core (~> 2.2)
18
+ rspec-expectations (~> 2.2)
19
+ rspec-mocks (~> 2.2)
20
+ rspec-core (2.2.1)
21
+ rspec-expectations (2.2.0)
22
+ diff-lcs (~> 1.1.2)
23
+ rspec-mocks (2.2.0)
24
+ uuid (2.3.1)
25
+ macaddr (~> 1.0)
26
+
27
+ PLATFORMS
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ RedCloth
32
+ bundler (~> 1.0.0)
33
+ jeweler (~> 1.5.1)
34
+ linguistics
35
+ liquid
36
+ rcov
37
+ rspec (~> 2.2.0)
38
+ uuid
data/LICENSE.txt ADDED
@@ -0,0 +1,26 @@
1
+ Copyright (c) 2010 Jason LaPier
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+
23
+ NOTE:
24
+ Some open source fonts are included for embedding in epubs. Please
25
+ refer to the license file for usage, found here:
26
+ templates/OEBPS/fonts/licenses.txt
data/README.rdoc ADDED
@@ -0,0 +1,41 @@
1
+ = epubbery
2
+
3
+ Generates a template directory that you can use to build a custom epub file.
4
+
5
+ Usage:
6
+ new_book /path/to/new/book
7
+ (if the directory does not exist, it will be created)
8
+
9
+ Go to the new directory and modify the file config.yml
10
+
11
+ Run gen_epub from within the new directory.
12
+
13
+ Text files will be html-ized using textile (via the RedCloth gem). Check the templates directory for files you may want to customize (such as stylesheet.css or the .liquid html files).
14
+
15
+ == Converting to PDF
16
+
17
+ After you've created an epub file, you can easily convert it to PDF. Here are a couple of hints:
18
+
19
+ using Calibre (http://calibre-ebook.com/):
20
+ ebook-convert epub_folder/file_name.epub .pdf --custom-size=5x8 --base-font-size=12 --margin-top=54 --margin-left=54 --margin-bottom=54 --margin-right=54
21
+
22
+ using wkhtmltopdf (http://code.google.com/p/wkhtmltopdf/):
23
+ wkhtmltopdf --page-width 5in --page-height 8in -L 0.5in -R 0.5in -B 0.5in -T 0.25in --footer-center '[page]' --footer-spacing 2 --print-media-type --footer-font-name TexGyreTermes --footer-font-size 9 epub_folder/OEBPS/*.html mybook.pdf
24
+
25
+
26
+
27
+ == Contributing to epubbery
28
+
29
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
30
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
31
+ * Fork the project
32
+ * Start a feature/bugfix branch
33
+ * Commit and push until you are happy with your contribution
34
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
35
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
36
+
37
+ == Copyright
38
+
39
+ Copyright (c) 2010 Jason LaPier. See LICENSE.txt for
40
+ further details.
41
+
data/Rakefile ADDED
@@ -0,0 +1,55 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "epubbery"
16
+ gem.homepage = "http://github.com/jlapier/epubbery"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{Generate epub skeleton, convert plain text files into xhtml and create epub}
19
+ gem.description = %Q{Generates a template directory that you can use to build a custom epub.
20
+ After customizing templates, use bin/gen_epub.rb to create and validate an epub archive.}
21
+ gem.email = "jason.lapier@gmail.com"
22
+ gem.authors = ["Jason LaPier"]
23
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
24
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
25
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
26
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
27
+ gem.add_runtime_dependency 'RedCloth'
28
+ gem.add_runtime_dependency 'liquid'
29
+ gem.add_runtime_dependency 'uuid'
30
+ gem.add_runtime_dependency 'linguistics'
31
+ end
32
+ Jeweler::RubygemsDotOrgTasks.new
33
+
34
+ require 'rspec/core'
35
+ require 'rspec/core/rake_task'
36
+ RSpec::Core::RakeTask.new(:spec) do |spec|
37
+ spec.pattern = FileList['spec/**/*_spec.rb']
38
+ end
39
+
40
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
41
+ spec.pattern = 'spec/**/*_spec.rb'
42
+ spec.rcov = true
43
+ end
44
+
45
+ task :default => :spec
46
+
47
+ require 'rake/rdoctask'
48
+ Rake::RDocTask.new do |rdoc|
49
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
50
+
51
+ rdoc.rdoc_dir = 'rdoc'
52
+ rdoc.title = "epubbery #{version}"
53
+ rdoc.rdoc_files.include('README*')
54
+ rdoc.rdoc_files.include('lib/**/*.rb')
55
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.2
data/bin/epubbery ADDED
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/ruby
2
+
3
+ @gem_dir = File.expand_path(File.dirname(__FILE__) + '/..')
4
+
5
+ $: << File.join(@gem_dir, 'lib')
6
+
7
+ require 'fileutils'
8
+ require File.join(@gem_dir, 'lib', 'epubbery')
9
+
10
+ include EpubSetup
11
+
12
+ if ARGV[0]
13
+ @destination = ARGV[0]
14
+ @base_dir = File.expand_path(File.dirname(__FILE__) + '/..')
15
+
16
+ puts "Creating templates..."
17
+ FileUtils.mkdir_p @destination
18
+ puts "Copying necessary files..."
19
+ FileUtils.cp_r File.join(@base_dir, 'templates'), @destination
20
+ FileUtils.cp_r File.join(@base_dir, 'lib'), @destination
21
+ FileUtils.cp_r File.join(@base_dir, 'bin'), @destination
22
+ FileUtils.cp File.join(@base_dir, 'config_sample.yml'), File.join(@destination, 'config.yml')
23
+
24
+ puts "Done! Go to #{@destination} and edit config.yml and then run epubbery from that directory."
25
+ elsif File.exist?('config.yml')
26
+ @config = YAML::load(File.read('config.yml'))
27
+ @epub_folder = File.join(Dir.getwd, @config[:temp_epub_folder])
28
+
29
+ make_skeleton Dir.getwd, @epub_folder
30
+
31
+ @book = Book.new @config[:book_title], @config[:author]
32
+ @book.chapters = EpubSetup::read_chapters(@config[:chapter_glob])
33
+
34
+ write_templates(@book)
35
+
36
+ # TODO: use rubyzip or zipruby or something - they all seem to be a PITA compared to unix zip
37
+
38
+ FileUtils.cd @epub_folder
39
+ FileUtils.rm @config[:file_name] if File.exists?(@config[:file_name])
40
+
41
+ puts "\nGenerating #{@epub_folder}/#{@config[:file_name]}"
42
+
43
+ system "zip -0Xq #{@config[:file_name]} mimetype"
44
+ system "zip -Xr9Dq #{@config[:file_name]} *"
45
+
46
+ puts "\nRunning epubcheck..."
47
+ system "java -jar #{@config[:epubcheck]} #{@config[:file_name]}"
48
+ else
49
+ puts "USAGE:\n"
50
+ puts "To create a new epubbery project, run:"
51
+ puts " epubbery /path/to/new/epub/project\n"
52
+ puts "To generate an epub from inside an epubbery project, run:"
53
+ puts " epubbery"
54
+ puts "(a config.yml file is required in the same directory)"
55
+ exit
56
+ end
57
+
data/config_sample.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ :book_title: My Book Title
3
+ :author: My Name
4
+ :epubcheck: /opt/epubcheck/epubcheck-1.1.jar
5
+ :file_name: mybook.epub
6
+ :chapter_glob: ~/some/path/*.txt
7
+ :temp_epub_folder: epub
data/epubbery.gemspec ADDED
@@ -0,0 +1,126 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{epubbery}
8
+ s.version = "0.1.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Jason LaPier"]
12
+ s.date = %q{2011-06-10}
13
+ s.default_executable = %q{epubbery}
14
+ s.description = %q{Generates a template directory that you can use to build a custom epub.
15
+ After customizing templates, use bin/gen_epub.rb to create and validate an epub archive.}
16
+ s.email = %q{jason.lapier@gmail.com}
17
+ s.executables = ["epubbery"]
18
+ s.extra_rdoc_files = [
19
+ "LICENSE.txt",
20
+ "README.rdoc"
21
+ ]
22
+ s.files = [
23
+ ".document",
24
+ ".rspec",
25
+ "Gemfile",
26
+ "Gemfile.lock",
27
+ "LICENSE.txt",
28
+ "README.rdoc",
29
+ "Rakefile",
30
+ "VERSION",
31
+ "bin/epubbery",
32
+ "config_sample.yml",
33
+ "epubbery.gemspec",
34
+ "lib/book.rb",
35
+ "lib/chapter.rb",
36
+ "lib/epub_setup.rb",
37
+ "lib/epubbery.rb",
38
+ "spec/book_spec.rb",
39
+ "spec/chapter_spec.rb",
40
+ "spec/epub_setup_spec.rb",
41
+ "spec/spec_helper.rb",
42
+ "templates/META-INF/container.xml",
43
+ "templates/OEBPS/chapter.html.liquid",
44
+ "templates/OEBPS/content.opf.liquid",
45
+ "templates/OEBPS/end_of_book.html.liquid",
46
+ "templates/OEBPS/fonts.css",
47
+ "templates/OEBPS/fonts/BergamoStd-Bold.otf",
48
+ "templates/OEBPS/fonts/BergamoStd-BoldItalic.otf",
49
+ "templates/OEBPS/fonts/BergamoStd-Italic.otf",
50
+ "templates/OEBPS/fonts/BergamoStd-Regular.otf",
51
+ "templates/OEBPS/fonts/OFLGoudyStM-Italic.otf",
52
+ "templates/OEBPS/fonts/OFLGoudyStM.otf",
53
+ "templates/OEBPS/fonts/licenses.txt",
54
+ "templates/OEBPS/fonts/texgyrepagella-bold.otf",
55
+ "templates/OEBPS/fonts/texgyrepagella-bolditalic.otf",
56
+ "templates/OEBPS/fonts/texgyrepagella-italic.otf",
57
+ "templates/OEBPS/fonts/texgyrepagella-regular.otf",
58
+ "templates/OEBPS/fonts/texgyretermes-bold.otf",
59
+ "templates/OEBPS/fonts/texgyretermes-bolditalic.otf",
60
+ "templates/OEBPS/fonts/texgyretermes-italic.otf",
61
+ "templates/OEBPS/fonts/texgyretermes-regular.otf",
62
+ "templates/OEBPS/images/made_by_obf.jpg",
63
+ "templates/OEBPS/print.css",
64
+ "templates/OEBPS/stylesheet.css",
65
+ "templates/OEBPS/title.html.liquid",
66
+ "templates/OEBPS/toc.ncx.liquid",
67
+ "templates/mimetype"
68
+ ]
69
+ s.homepage = %q{http://github.com/jlapier/epubbery}
70
+ s.licenses = ["MIT"]
71
+ s.require_paths = ["lib"]
72
+ s.rubygems_version = %q{1.5.0}
73
+ s.summary = %q{Generate epub skeleton, convert plain text files into xhtml and create epub}
74
+ s.test_files = [
75
+ "spec/book_spec.rb",
76
+ "spec/chapter_spec.rb",
77
+ "spec/epub_setup_spec.rb",
78
+ "spec/spec_helper.rb"
79
+ ]
80
+
81
+ if s.respond_to? :specification_version then
82
+ s.specification_version = 3
83
+
84
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
85
+ s.add_runtime_dependency(%q<RedCloth>, [">= 0"])
86
+ s.add_runtime_dependency(%q<liquid>, [">= 0"])
87
+ s.add_runtime_dependency(%q<uuid>, [">= 0"])
88
+ s.add_runtime_dependency(%q<linguistics>, [">= 0"])
89
+ s.add_development_dependency(%q<rspec>, ["~> 2.2.0"])
90
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
91
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.1"])
92
+ s.add_development_dependency(%q<rcov>, [">= 0"])
93
+ s.add_runtime_dependency(%q<RedCloth>, [">= 0"])
94
+ s.add_runtime_dependency(%q<liquid>, [">= 0"])
95
+ s.add_runtime_dependency(%q<uuid>, [">= 0"])
96
+ s.add_runtime_dependency(%q<linguistics>, [">= 0"])
97
+ else
98
+ s.add_dependency(%q<RedCloth>, [">= 0"])
99
+ s.add_dependency(%q<liquid>, [">= 0"])
100
+ s.add_dependency(%q<uuid>, [">= 0"])
101
+ s.add_dependency(%q<linguistics>, [">= 0"])
102
+ s.add_dependency(%q<rspec>, ["~> 2.2.0"])
103
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
104
+ s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
105
+ s.add_dependency(%q<rcov>, [">= 0"])
106
+ s.add_dependency(%q<RedCloth>, [">= 0"])
107
+ s.add_dependency(%q<liquid>, [">= 0"])
108
+ s.add_dependency(%q<uuid>, [">= 0"])
109
+ s.add_dependency(%q<linguistics>, [">= 0"])
110
+ end
111
+ else
112
+ s.add_dependency(%q<RedCloth>, [">= 0"])
113
+ s.add_dependency(%q<liquid>, [">= 0"])
114
+ s.add_dependency(%q<uuid>, [">= 0"])
115
+ s.add_dependency(%q<linguistics>, [">= 0"])
116
+ s.add_dependency(%q<rspec>, ["~> 2.2.0"])
117
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
118
+ s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
119
+ s.add_dependency(%q<rcov>, [">= 0"])
120
+ s.add_dependency(%q<RedCloth>, [">= 0"])
121
+ s.add_dependency(%q<liquid>, [">= 0"])
122
+ s.add_dependency(%q<uuid>, [">= 0"])
123
+ s.add_dependency(%q<linguistics>, [">= 0"])
124
+ end
125
+ end
126
+
data/lib/book.rb ADDED
@@ -0,0 +1,30 @@
1
+ # Book: contains info like title and creator
2
+ # also contains an array of chapters (Chapter class)
3
+ class Book
4
+ attr_accessor :title, :creator, :chapters, :pub_date, :pub_year, :isbn
5
+ liquid_methods :title, :creator, :chapters, :pub_date, :pub_year, :book_id, :cc_url
6
+
7
+ def initialize(title, creator, pub_date = Date.today, isbn = nil)
8
+ self.title = title
9
+ self.creator = creator
10
+ self.pub_date = pub_date
11
+ self.isbn = isbn
12
+ end
13
+
14
+ def book_id
15
+ @book_id ||= (isbn || "urn:uuid:#{UUID.new.generate}")
16
+ end
17
+
18
+ def pub_year
19
+ pub_date.year
20
+ end
21
+
22
+ def cc_url
23
+ # attribution only, free to distribute, modify, or use commercially:
24
+ # "http://creativecommons.org/licenses/by/3.0/"
25
+
26
+ # free to share with attribution, non-commercial, no derivatives
27
+ "http://creativecommons.org/licenses/by-nc-nd/3.0/"
28
+ end
29
+ end
30
+
data/lib/chapter.rb ADDED
@@ -0,0 +1,66 @@
1
+ # Chapter
2
+ # contains name, content (text-only)
3
+ # generates html
4
+ # file_name should reference html file after it is written
5
+ class Chapter
6
+ attr_accessor :number, :meta, :file_name, :content
7
+ liquid_methods :number, :meta, :file_name, :word_count, :html, :chapter_id,
8
+ :number_as_word, :number_or_name, :name_or_number
9
+
10
+ def initialize(lines)
11
+ self.meta = {}
12
+ meta = true
13
+ while meta and line = lines.shift do
14
+ line.strip!
15
+ matches = line.match /^(.+):\s+(.+)/
16
+ if matches
17
+ if matches[1] =~ /(Chapter|Number|Position)/i and matches[2] =~ /\d+/ and number.nil?
18
+ self.number = matches[2].strip.to_i
19
+ end
20
+ self.meta[matches[1].downcase] = matches[2]
21
+ else
22
+ lines = [line] + lines if line
23
+ meta = false
24
+ end
25
+ end
26
+
27
+ self.content = lines.join
28
+ end
29
+
30
+ def word_count
31
+ @word_count ||= (name + content).gsub(/(_|\*|,|:)/, '').scan(/(\w|-|')+/).size
32
+ end
33
+
34
+ def html
35
+ content.strip!
36
+ @html ||= RedCloth.new(content).to_html
37
+ end
38
+
39
+ def chapter_id
40
+ @book_id ||= file_name.gsub(/\W/,'_').gsub('.html', '')
41
+ end
42
+
43
+ def number_as_word
44
+ number ? Linguistics::EN.numwords(number).capitalize : nil
45
+ end
46
+
47
+ def name
48
+ meta['name'] || ""
49
+ end
50
+
51
+ # if there is a number, give us that written out as words; otherwise give the chapter name
52
+ def number_or_name
53
+ number ? "Chapter #{number_as_word}" : name
54
+ end
55
+
56
+ # if there is a name, give us that; otherwise give the number written out as words
57
+ def name_or_number
58
+ if !name.empty?
59
+ name
60
+ elsif number
61
+ "Chapter #{number_as_word}"
62
+ else
63
+ ""
64
+ end
65
+ end
66
+ end
data/lib/epub_setup.rb ADDED
@@ -0,0 +1,70 @@
1
+ # EpubSetup
2
+ # making directories and moving files and whatnot
3
+ module EpubSetup
4
+ def make_skeleton(base_dir, epub_folder)
5
+ @epub_folder = epub_folder
6
+ @source_templates_dir = File.join(base_dir, 'templates')
7
+ @target_meta_dir = File.join(@epub_folder, 'META-INF')
8
+ @target_oebps_dir = File.join(@epub_folder, 'OEBPS')
9
+
10
+ FileUtils.rm_rf @epub_folder if File.exists?(@epub_folder)
11
+ FileUtils.mkdir_p @epub_folder
12
+ FileUtils.mkdir_p @target_meta_dir
13
+ FileUtils.mkdir_p @target_oebps_dir
14
+
15
+ FileUtils.cp File.join(@source_templates_dir, 'mimetype'), @epub_folder
16
+ FileUtils.cp File.join(@source_templates_dir, 'META-INF', 'container.xml'), @target_meta_dir
17
+
18
+ # TODO - somehow detect these "asset" folders and files -
19
+ # for now they are these defaults: css, images, fonts
20
+ FileUtils.cp Dir[File.join(@source_templates_dir, 'OEBPS', '*.css')], @target_oebps_dir
21
+ FileUtils.cp_r File.join(@source_templates_dir, 'OEBPS', 'images'), @target_oebps_dir
22
+ FileUtils.cp_r File.join(@source_templates_dir, 'OEBPS', 'fonts'), @target_oebps_dir
23
+
24
+ # liquid templates for rest of files
25
+ @chapter_liq_template = Liquid::Template.parse(File.read(File.join(@source_templates_dir, 'OEBPS', 'chapter.html.liquid' )))
26
+ @content_liq_template = Liquid::Template.parse(File.read(File.join(@source_templates_dir, 'OEBPS', 'content.opf.liquid' )))
27
+ @title_liq_template = Liquid::Template.parse(File.read(File.join(@source_templates_dir, 'OEBPS', 'title.html.liquid' )))
28
+ @toc_liq_template = Liquid::Template.parse(File.read(File.join(@source_templates_dir, 'OEBPS', 'toc.ncx.liquid' )))
29
+ @eob_liq_template = Liquid::Template.parse(File.read(File.join(@source_templates_dir, 'OEBPS', 'end_of_book.html.liquid')))
30
+ end
31
+
32
+ def read_chapters(file_glob)
33
+ file_glob = File.expand_path(file_glob)
34
+ puts "Reading files: #{file_glob} (#{Dir[file_glob].size} files found)"
35
+ chapters = []
36
+
37
+ Dir[file_glob].each do |txtfile|
38
+ chapter = nil
39
+ File.open(txtfile) do |f|
40
+ chapter = Chapter.new(f.readlines)
41
+ chapter.file_name = "#{File.basename(txtfile, '.txt')}.html"
42
+ end
43
+ chapters << chapter if chapter
44
+ end
45
+
46
+ # returns chapters as an array sorted by name
47
+ chapters.sort_by { |c| [c.number || 0, c.name || '', c.file_name] }
48
+ end
49
+
50
+ def write_templates(book)
51
+ book.chapters.each do |chapter|
52
+ html_output = @chapter_liq_template.render 'chapter' => chapter
53
+ puts "Writing: #{@epub_folder}/OEBPS/#{chapter.file_name}"
54
+ File.open(File.join(@target_oebps_dir, chapter.file_name), "w") { |f| f.puts html_output }
55
+ end
56
+
57
+ puts "Writing: #{@epub_folder}/OEBPS/content.opf"
58
+ File.open(File.join(@target_oebps_dir, 'content.opf'), "w") { |f| f.puts @content_liq_template.render('book' => book,
59
+ 'css_files' => Dir[File.join(@source_templates_dir, 'OEBPS', '*.css')].map { |f| File.basename(f) },
60
+ 'image_files' => Dir[File.join(@source_templates_dir, 'OEBPS', 'images', '*')].map { |f| File.basename(f) },
61
+ 'font_files' => Dir[File.join(@source_templates_dir, 'OEBPS', 'fonts', '*')].map { |f| File.basename(f) } ) }
62
+ puts "Writing: #{@epub_folder}/OEBPS/title.html"
63
+ File.open(File.join(@target_oebps_dir, 'title.html'), "w") { |f| f.puts @title_liq_template.render('book' => book) }
64
+ puts "Writing: #{@epub_folder}/OEBPS/end_of_book.html"
65
+ File.open(File.join(@target_oebps_dir, 'end_of_book.html'), "w") { |f| f.puts @eob_liq_template.render('book' => book) }
66
+ puts "Writing: #{@epub_folder}/OEBPS/toc.ncx"
67
+ File.open(File.join(@target_oebps_dir, 'toc.ncx'), "w") { |f| f.puts @toc_liq_template.render('book' => book) }
68
+ end
69
+ end
70
+
data/lib/epubbery.rb ADDED
@@ -0,0 +1,16 @@
1
+ # gems
2
+ require 'rubygems'
3
+ require 'liquid'
4
+ require 'RedCloth'
5
+ require 'linguistics'
6
+ require 'uuid'
7
+
8
+ # ruby libs
9
+ require 'fileutils'
10
+ require 'date'
11
+
12
+ # epubbery libs
13
+ require 'book'
14
+ require 'chapter'
15
+ require 'epub_setup'
16
+
data/spec/book_spec.rb ADDED
@@ -0,0 +1,25 @@
1
+ #require File.expand_path(File.dirname(__FILE__) + '/../lib/boot')
2
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
+
4
+ describe Book do
5
+ before(:each) do
6
+ end
7
+
8
+ it "should init with basic data" do
9
+ book = Book.new "Title", "Joe", Date.new(2010, 5)
10
+ book.title.should == "Title"
11
+ book.creator.should == "Joe"
12
+ book.pub_date.to_s.should == "2010-05-01"
13
+ book.pub_year.should == 2010
14
+ book.cc_url.should == "http://creativecommons.org/licenses/by-nc-nd/3.0/"
15
+ the_id = book.book_id
16
+ the_id.should =~ /^urn:uuid:.+/
17
+ book.book_id.should == the_id
18
+ end
19
+
20
+ it "should use an isbn if one is given" do
21
+ book = Book.new "Title 2", "Jack", Date.new(2009), "123456789X"
22
+ book.book_id.should == "123456789X"
23
+ end
24
+ end
25
+
@@ -0,0 +1,65 @@
1
+ #require File.expand_path(File.dirname(__FILE__) + '/../lib/boot')
2
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
+
4
+ describe Chapter do
5
+ before(:each) do
6
+ lines_with_meta = <<-EOF
7
+ Chapter: 13
8
+ Name: This is a Chapter with Meta
9
+ Subhead: Created on November 20th
10
+
11
+ "It all began a long time ago," he said.
12
+
13
+ And he _told_ his tale.
14
+ EOF
15
+ @file_lines_with_meta = lines_with_meta.split("\n")
16
+
17
+
18
+ lines_without_meta = <<-EOF
19
+ "It all began a long time ago," he said.
20
+
21
+ And he _told_ his tale.
22
+ EOF
23
+
24
+ @file_lines_without_meta = lines_without_meta.split("\n")
25
+ end
26
+
27
+ it "should init with meta" do
28
+ chapter = Chapter.new(@file_lines_with_meta)
29
+ chapter.number.should == 13
30
+ chapter.name.should == "This is a Chapter with Meta"
31
+ chapter.meta['subhead'].should == "Created on November 20th"
32
+ chapter.content.should include('began a long time')
33
+ chapter.content.should include('his tale')
34
+ end
35
+
36
+ it "should init without meta" do
37
+ chapter = Chapter.new(@file_lines_without_meta)
38
+ chapter.number.should be(nil)
39
+ chapter.name.should == ''
40
+ chapter.number_or_name.should == ""
41
+ chapter.name_or_number.should == ""
42
+ chapter.meta['subhead'].should be(nil)
43
+ chapter.content.should include('began a long time')
44
+ chapter.content.should include('his tale')
45
+ end
46
+
47
+ it "should use redcloth to process text" do
48
+ chapter = Chapter.new(@file_lines_with_meta)
49
+ chapter.html.should include('<p>')
50
+ chapter.content.should include('_told_ his tale')
51
+ chapter.html.should include('<em>told</em> his tale')
52
+ end
53
+
54
+ it "should have some name and number helper methods" do
55
+ chapter = Chapter.new(@file_lines_with_meta)
56
+ chapter.number_or_name.should == "Chapter Thirteen"
57
+ chapter.name_or_number.should == "This is a Chapter with Meta"
58
+ end
59
+
60
+ it "should count words" do
61
+ chapter = Chapter.new(@file_lines_without_meta)
62
+ chapter.word_count.should == 14
63
+ end
64
+ end
65
+