bookshelf 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ .DS_Store
2
+ pkg
3
+ tmp
4
+ spec/support/mybook/output/mybook.*
@@ -0,0 +1,3 @@
1
+ [submodule "lib/bookshelf/vendor/colorize"]
2
+ path = lib/bookshelf/vendor/colorize
3
+ url = git://github.com/fnando/colorize.git
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
@@ -0,0 +1,66 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ bookshelf (1.0.4)
5
+ RedCloth
6
+ activesupport
7
+ coderay
8
+ eeepub-with-cover-support
9
+ i18n
10
+ nokogiri
11
+ notifier
12
+ rdiscount
13
+ thor
14
+
15
+ GEM
16
+ remote: https://rubygems.org/
17
+ specs:
18
+ RedCloth (4.2.9)
19
+ activesupport (3.2.12)
20
+ i18n (~> 0.6)
21
+ multi_json (~> 1.0)
22
+ awesome_print (1.1.0)
23
+ builder (3.2.0)
24
+ coderay (1.0.9)
25
+ diff-lcs (1.2.2)
26
+ eeepub-with-cover-support (0.8.7)
27
+ builder
28
+ rubyzip
29
+ i18n (0.6.4)
30
+ method_source (0.8.1)
31
+ multi_json (1.7.2)
32
+ nokogiri (1.5.9)
33
+ notifier (0.4.1)
34
+ pry (0.9.12)
35
+ coderay (~> 1.0.5)
36
+ method_source (~> 0.8)
37
+ slop (~> 3.4)
38
+ pry-nav (0.2.3)
39
+ pry (~> 0.9.10)
40
+ rake (10.0.4)
41
+ rdiscount (2.0.7.1)
42
+ rspec (2.13.0)
43
+ rspec-core (~> 2.13.0)
44
+ rspec-expectations (~> 2.13.0)
45
+ rspec-mocks (~> 2.13.0)
46
+ rspec-core (2.13.1)
47
+ rspec-expectations (2.13.0)
48
+ diff-lcs (>= 1.1.3, < 2.0)
49
+ rspec-mocks (2.13.0)
50
+ rubyzip (0.9.9)
51
+ slop (3.4.4)
52
+ test_notifier (1.0.1)
53
+ notifier
54
+ thor (0.18.1)
55
+
56
+ PLATFORMS
57
+ ruby
58
+
59
+ DEPENDENCIES
60
+ awesome_print
61
+ bookshelf!
62
+ pry
63
+ pry-nav
64
+ rake
65
+ rspec
66
+ test_notifier
@@ -0,0 +1,162 @@
1
+ # Bookshelf
2
+
3
+ Bookshelf is a tool for the self-publishing of books. It is inspired by (and heavily based off) the excellent Kitabu gem [https://github.com/fnando/kitabu]().
4
+
5
+ ## Features
6
+ * Generate HTML, PDF, e-Pub, Mobi and Text files
7
+ * Multi book support
8
+ * Write using Markdown, Textile or plain HTML
9
+ * Book layout support
10
+ * Custom font support
11
+ * SCSS support
12
+ * Table of Contents generation
13
+
14
+ ## Installation
15
+
16
+ To install Bookshelf, you’ll need a working Ruby 1.9+ installation.
17
+ If you’re cool with it, just run the following command to install it.
18
+
19
+ gem install bookshelf
20
+
21
+ After installing Bookshelf, run the following command to check your external
22
+ dependencies.
23
+
24
+ $ bookshelf check
25
+
26
+ Prince XML: Converts HTML files into PDF files.
27
+ Installed.
28
+
29
+ KindleGen: Converts ePub e-books into .mobi files.
30
+ Installed.
31
+
32
+ html2text: Converts HTML documents into plain text.
33
+ Not installed.
34
+
35
+ There's no requirements here; just make sure you cleared the correct dependency based
36
+ on the formats you want to export to.
37
+
38
+ ## Getting Started
39
+
40
+ We first need to generate a new bookshelf project
41
+
42
+ $ bookshelf new my_bookshelf
43
+
44
+ This command creates a directory `my_bookshelf` with the following structure:
45
+
46
+ my_bookshelf
47
+ ├── assets
48
+ │ ├── fonts
49
+ │ ├── images
50
+ │ └── styles
51
+ │ ├── _fonts.scss
52
+ │ ├── epub.scss
53
+ │ └── html.scss
54
+ ├── books
55
+ ├── config
56
+ │ ├── config.yml
57
+ │ └── helper.rb
58
+ ├── output
59
+ └── templates
60
+ ├── epub
61
+ │ ├── cover.erb
62
+ │ ├── page.erb
63
+ └── html
64
+ └── layout.erb
65
+
66
+ ## Creating a new Book
67
+
68
+ To add a book create a folder under the `books` directory, named as per the title.
69
+
70
+ my_bookshelf
71
+ └── books
72
+ └── my_book
73
+
74
+ Copy the `config.yml` file from `my_bookshelf/config/config.yml` into `my_bookshelf/books/my_book`
75
+
76
+ Update `my_bookshelf/config/config.yml` to reflect the books title, author and other attributes.
77
+
78
+ ## Authoring
79
+
80
+ Now, create the content for your book by creating markdown or textile files into the `my_bookshelf/books/my_book` directory. You have two options here but both are dependent on the numeric prefix assigned to the file to determine their order.
81
+
82
+ *Option 1 - Directories for chapters:*
83
+
84
+ my_bookshelf
85
+ └── books
86
+ └── my_book
87
+ ├── 01_introduction
88
+ │ ├── 01_section_1.markdown
89
+ │ ├── 02_section_2.markdown
90
+ │ └── ...
91
+ ├── 02_chapter_1
92
+ │ ├── 01_section_1.markdown
93
+ │ ├── 02_section_2.markdown
94
+ │ └── ...
95
+ ├── 03_chapter_2
96
+ ├── 04_chapter_3
97
+ └── ...
98
+
99
+ *Option 2 - Files for chapters:*
100
+
101
+ my_bookshelf
102
+ └── books
103
+ └── my_book
104
+ ├── 01_introduction.markdown
105
+ ├── 02_chapter_1.markdown
106
+ ├── 03_chapter_2.markdown
107
+ ├── 04_chapter_3.markdown
108
+ └── ...
109
+
110
+ Note that you if the number of chapters in your book is likely to exceed 10, you should add an extra 0 to the front of the chapter directory/file names
111
+
112
+ Note that you can use any format you want at the same time. Just use one of the following extensions: `.html`, `.markdown`, `.mkdn` or `.textile`.
113
+
114
+ ## Exporting
115
+
116
+ You'll want to see your progress eventually; it's time for you to generate the book PDF. Just run the command `bookshelf export` and your book will be created in the `output` directory.
117
+
118
+ Bookshelf can generate a Table of Contents (TOC) based on your `h2-h6` tags. The `h1` tag is discarded because it's meant to be the book title.
119
+
120
+ To print the TOC, you need to print a variable called `toc`, using the eRb tag.
121
+
122
+ <%= toc %>
123
+
124
+ ## Markdown Processors
125
+
126
+ By default, RDiscount[http://github.com/rtomayko/rdiscount/tree/master] is the Markdown processor. However, you can switch to different implementations by simply installing any of the following processors:
127
+
128
+ * Maruku: https://rubygems.org/gems/maruku
129
+ * PEGMarkdown: https://rubygems.org/gems/rpeg-markdown
130
+ * BlueCloth: https://rubygems.org/gems/bluecloth
131
+ * Redcarpet: https://rubygems.org/gems/redcarpet
132
+
133
+ Note: RDiscount will always be installed as Bookshelf's dependency but only used when no
134
+ alternative library is available.
135
+
136
+ ## References
137
+
138
+ * Textile: http://hobix.com/textile
139
+ * Markdown: http://daringfireball.net/projects/markdown/syntax
140
+
141
+ ## License
142
+
143
+ (The MIT License)
144
+
145
+ Permission is hereby granted, free of charge, to any person obtaining
146
+ a copy of this software and associated documentation files (the
147
+ 'Software'), to deal in the Software without restriction, including
148
+ without limitation the rights to use, copy, modify, merge, publish,
149
+ distribute, sublicense, and/or sell copies of the Software, and to
150
+ permit persons to whom the Software is furnished to do so, subject to
151
+ the following conditions:
152
+
153
+ The above copyright notice and this permission notice shall be
154
+ included in all copies or substantial portions of the Software.
155
+
156
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
157
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
158
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
159
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
160
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
161
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
162
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,5 @@
1
+ require "bundler"
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require "rspec/core/rake_task"
5
+ RSpec::Core::RakeTask.new
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- mode: ruby -*-
3
+
4
+ require "bookshelf"
5
+ Bookshelf::Cli.start
@@ -0,0 +1,37 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "bookshelf/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "bookshelf"
7
+ s.version = Bookshelf::Version::STRING
8
+ s.platform = Gem::Platform::RUBY
9
+ s.required_ruby_version = ">= 1.9"
10
+ s.authors = ["Brad Crawford"]
11
+ s.email = ["brad.robert.crawford@gmail.com"]
12
+ s.homepage = "https://bitbucket.org/bradcrawford/bookshelf"
13
+ s.summary = "A framework that generates PDF and e-Pub from Markdown, Textile, and HTML files."
14
+ s.description = s.summary
15
+ s.license = "MIT"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency "activesupport"
23
+ s.add_dependency "nokogiri"
24
+ s.add_dependency "RedCloth"
25
+ s.add_dependency "rdiscount"
26
+ s.add_dependency "i18n"
27
+ s.add_dependency "thor"
28
+ s.add_dependency "eeepub-with-cover-support"
29
+ s.add_dependency "notifier"
30
+
31
+ s.add_development_dependency "rspec"
32
+ s.add_development_dependency "test_notifier"
33
+ s.add_development_dependency "rake"
34
+ s.add_development_dependency "pry"
35
+ s.add_development_dependency "pry-nav"
36
+ s.add_development_dependency "awesome_print"
37
+ end
@@ -0,0 +1,64 @@
1
+ require "active_support/all"
2
+ require "digest/md5"
3
+ require "eeepub"
4
+ require "erb"
5
+ require "logger"
6
+ require "nokogiri"
7
+ require "notifier"
8
+ require "open3"
9
+ require "optparse"
10
+ require "ostruct"
11
+ require "RedCloth"
12
+ require "tempfile"
13
+ require "pathname"
14
+ require "thor"
15
+ require "thor/group"
16
+ require "yaml"
17
+ require "cgi"
18
+
19
+ %w[maruku peg_markdown bluecloth redcarpet rdiscount].each do |lib|
20
+ begin
21
+ require lib
22
+ break
23
+ rescue LoadError => e
24
+ next
25
+ end
26
+ end
27
+
28
+ Encoding.default_internal = "utf-8"
29
+ Encoding.default_external = "utf-8"
30
+
31
+ module Bookshelf
32
+ require "bookshelf/extensions/string"
33
+ require "bookshelf/extensions/redcloth"
34
+ require "bookshelf/errors"
35
+
36
+ ROOT = Pathname.new(File.dirname(__FILE__) + "/..")
37
+
38
+ autoload :Version, "bookshelf/version"
39
+ autoload :Generator, "bookshelf/generator"
40
+ autoload :TOC, "bookshelf/toc"
41
+ autoload :Cli, "bookshelf/cli"
42
+ autoload :Markdown, "bookshelf/adapters/markdown"
43
+ autoload :Parser, "bookshelf/parser"
44
+ autoload :Exporter, "bookshelf/exporter"
45
+ autoload :Syntax, "bookshelf/syntax"
46
+ autoload :Stream, "bookshelf/stream"
47
+ autoload :Dependency, "bookshelf/dependency"
48
+ autoload :Stats, "bookshelf/stats"
49
+
50
+ def self.config(book_dir = nil)
51
+ path = book_dir.join("config.yml")
52
+ content = File.read(path)
53
+ erb = ERB.new(content).result
54
+ YAML.load(erb).with_indifferent_access
55
+ end
56
+
57
+ def self.logger
58
+ @logger ||= Logger.new(File.open("/tmp/bookshelf.log", "a"))
59
+ end
60
+
61
+ def self.root_dir
62
+ @root_dir ||= Pathname.new(Dir.pwd)
63
+ end
64
+ end
@@ -0,0 +1,34 @@
1
+ module Bookshelf
2
+ class Markdown
3
+ # Supported Markdown libraries
4
+ #
5
+ MARKDOWN_LIBRARIES = %w[Maruku BlueCloth PEGMarkdown Redcarpet RDiscount]
6
+
7
+ # Retrieve preferred Markdown processor.
8
+ # You'll need one of the following libraries:
9
+ #
10
+ # # RDiscount: https://rubygems.org/gems/rdiscount
11
+ # # Maruku: https://rubygems.org/gems/maruku
12
+ # # PEGMarkdown: https://rubygems.org/gems/rpeg-markdown
13
+ # # BlueCloth: https://rubygems.org/gems/bluecloth
14
+ # # Redcarpet: https://rubygems.org/gems/redcarpet
15
+ #
16
+ # Note: RDiscount will always be installed as Bookshelf's dependency but only used when no
17
+ # alternative library is available.
18
+ #
19
+ def self.engine
20
+ @engine ||= Object.const_get(MARKDOWN_LIBRARIES.find {|lib| Object.const_defined?(lib)})
21
+ end
22
+
23
+ # Convert Markdown to HTML.
24
+ def self.to_html(content)
25
+ case engine.name
26
+ when "Redcarpet"
27
+ render = Redcarpet::Render::HTML.new(:hard_wrap => true, :xhtml => true)
28
+ Redcarpet::Markdown.new(render).render(content)
29
+ else
30
+ engine.new(content).to_html
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,125 @@
1
+ # -*- encoding: utf-8 -*-
2
+ module Bookshelf
3
+ class Cli < Thor
4
+ FORMATS = %w[pdf html epub mobi txt]
5
+ check_unknown_options!
6
+
7
+ def self.exit_on_failure?
8
+ true
9
+ end
10
+
11
+ def initialize(args = [], options = {}, config = {})
12
+ if (config[:current_task] || config[:current_command]).name == "new" && args.empty?
13
+ raise Error, "The e-Book path is required. For details run: bookshelf help new"
14
+ end
15
+
16
+ super
17
+ end
18
+
19
+ desc "new EBOOK_PATH", "Generate a new e-book structure"
20
+
21
+ def new(path)
22
+ generator = Generator.new
23
+ generator.destination_root = path
24
+ generator.invoke_all
25
+ end
26
+
27
+ desc "export [OPTIONS]", "Export e-book"
28
+ method_option :only, :type => :string, :desc => "Can be one of: #{FORMATS.join(", ")}"
29
+
30
+ def export
31
+ if options[:only] && !FORMATS.include?(options[:only])
32
+ raise Error, "The --only option need to be one of: #{FORMATS.join(", ")}"
33
+ end
34
+
35
+ book_dirs = if options[:book]
36
+ [Bookshelf.root_dir.join("books/#{options[:book]}")]
37
+ else
38
+ Dir.glob(Bookshelf.root_dir.join("books/*")).map{|book_dir| Pathname.new(book_dir) }
39
+ end
40
+
41
+ book_dirs.each do |book_dir|
42
+ Bookshelf::Exporter.run(book_dir, options)
43
+ end
44
+ end
45
+
46
+ desc "version", "Prints the Bookshelf's version information"
47
+ map %w(-v --version) => :version
48
+
49
+ def version
50
+ say "Bookshelf version #{Version::STRING}"
51
+ end
52
+
53
+ desc "check", "Check if all external dependencies are installed"
54
+
55
+ def check
56
+ result = []
57
+
58
+ result << {
59
+ :description => "Prince XML: Converts HTML files into PDF files.",
60
+ :installed => Bookshelf::Dependency.prince?
61
+ }
62
+
63
+ result << {
64
+ :description => "KindleGen: Converts ePub e-books into .mobi files.",
65
+ :installed => Bookshelf::Dependency.kindlegen?
66
+ }
67
+
68
+ result << {
69
+ :description => "html2text: Converts HTML documents into plain text.",
70
+ :installed => Bookshelf::Dependency.html2text?
71
+ }
72
+
73
+ result.each do |result|
74
+ text = color(result[:name], :blue)
75
+ text << "\n" << result[:description]
76
+ text << "\n" << (result[:installed] ? color("Installed.", :green) : color("Not installed.", :red))
77
+ text << "\n"
78
+
79
+ say(text)
80
+ end
81
+ end
82
+
83
+ desc "permalinks", "List title permalinks"
84
+
85
+ def permalinks
86
+ html = Bookshelf::Parser::HTML.new(Bookshelf.root_dir).content
87
+ toc = Bookshelf::TOC::HTML.generate(html)
88
+
89
+ toc.toc.each do |options|
90
+ level = options[:level] - 1
91
+ title = " #{options[:text]}: "
92
+ permalink = "##{options[:permalink]}"
93
+
94
+ text = "*" * level
95
+ text << color(title, :blue)
96
+ text << color(permalink, :yellow)
97
+ say(text)
98
+ end
99
+ end
100
+
101
+ desc "stats", "Display some stats about your e-book"
102
+ def stats
103
+ stats = Bookshelf::Stats.new(Bookshelf.root_dir)
104
+
105
+ say [
106
+ "Chapters: #{stats.chapters}",
107
+ "Words: #{stats.words}",
108
+ "Images: #{stats.images}",
109
+ "Links: #{stats.links}",
110
+ "Footnotes: #{stats.footnotes}",
111
+ "Code blocks: #{stats.code_blocks}"
112
+ ].join("\n")
113
+ end
114
+
115
+ private
116
+
117
+ def color(text, color)
118
+ color? ? shell.set_color(text, color) : text
119
+ end
120
+
121
+ def color?
122
+ shell.instance_of?(Thor::Shell::Color)
123
+ end
124
+ end
125
+ end