bookshelf 1.2.1 → 1.2.4
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.
- checksums.yaml +7 -0
- data/Gemfile.lock +23 -19
- data/README.md +6 -43
- data/bookshelf.gemspec +3 -4
- data/lib/bookshelf.rb +5 -18
- data/lib/bookshelf/adapters/markdown.rb +2 -20
- data/lib/bookshelf/cli.rb +2 -32
- data/lib/bookshelf/dependency.rb +0 -8
- data/lib/bookshelf/exporter.rb +1 -5
- data/lib/bookshelf/generator.rb +7 -6
- data/lib/bookshelf/parser.rb +1 -9
- data/lib/bookshelf/parser/epub.rb +166 -93
- data/lib/bookshelf/parser/html.rb +25 -102
- data/lib/bookshelf/parser/pdf.rb +2 -29
- data/lib/bookshelf/stats.rb +0 -8
- data/lib/bookshelf/version.rb +1 -1
- data/templates/cover.erb +6 -4
- data/templates/epub.erb +2 -2
- data/templates/helper.rb +0 -29
- data/templates/layout.erb +9 -17
- data/templates/toc.erb +20 -0
- metadata +179 -189
- data/lib/bookshelf/errors.rb +0 -3
- data/lib/bookshelf/extensions/redcloth.rb +0 -69
- data/lib/bookshelf/extensions/string.rb +0 -11
- data/lib/bookshelf/parser/mobi.rb +0 -14
- data/lib/bookshelf/parser/txt.rb +0 -18
- data/lib/bookshelf/stream.rb +0 -27
- data/lib/bookshelf/syntax.rb +0 -124
- data/lib/bookshelf/toc.rb +0 -6
- data/lib/bookshelf/toc/epub.rb +0 -41
- data/lib/bookshelf/toc/html.rb +0 -78
data/lib/bookshelf/errors.rb
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
module RedCloth
|
2
|
-
INLINE_FORMATTERS = [:textile, :footnote, :link]
|
3
|
-
|
4
|
-
def self.convert(text)
|
5
|
-
new(text).to_html(*INLINE_FORMATTERS)
|
6
|
-
end
|
7
|
-
|
8
|
-
module Inline
|
9
|
-
FN_RE = /
|
10
|
-
(\s+)? # getting spaces
|
11
|
-
(\\)?%\{ # opening
|
12
|
-
(.*?) # footnote
|
13
|
-
\}# # closing
|
14
|
-
/xm
|
15
|
-
|
16
|
-
def footnote(text)
|
17
|
-
text.gsub!(FN_RE) do |m|
|
18
|
-
if $2
|
19
|
-
%[#{$1}%{#{$3}}]
|
20
|
-
else
|
21
|
-
%(<span class="footnote">#{$3}</span>)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
LINK_RE = /
|
27
|
-
<
|
28
|
-
((?:https?|ftp):\/\/.*?)
|
29
|
-
>
|
30
|
-
/xm
|
31
|
-
|
32
|
-
def link(text)
|
33
|
-
text.gsub!(LINK_RE) do |m|
|
34
|
-
%(<a href="#{$1}">#{$1}</a>)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
module Formatters
|
40
|
-
module HTML
|
41
|
-
def figure(options = {})
|
42
|
-
%[<p class="figure"><img src="../images/#{options[:text]}" alt="#{options[:class]}" /><br/><span class="caption">#{options[:class]}</span></p>]
|
43
|
-
end
|
44
|
-
|
45
|
-
def note(options = {})
|
46
|
-
%[<p class="note">#{options[:text]}</p>]
|
47
|
-
end
|
48
|
-
|
49
|
-
def attention(options = {})
|
50
|
-
%[<p class="attention">#{options[:text]}</p>]
|
51
|
-
end
|
52
|
-
|
53
|
-
def file(options = {})
|
54
|
-
base_url = Bookshelf.config[:base_url]
|
55
|
-
|
56
|
-
if base_url
|
57
|
-
url = File.join(base_url, options[:text])
|
58
|
-
else
|
59
|
-
url = content
|
60
|
-
$stderr << "\nYou're using `file. #{content}` but didn't set base_url in your configuration file.\n"
|
61
|
-
end
|
62
|
-
|
63
|
-
%[<p class="file"><span><strong>Download</strong> <a href="#{url}">#{options[:text]}</a></span></p>]
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
RedCloth.send(:include, RedCloth::Inline)
|
@@ -1,11 +0,0 @@
|
|
1
|
-
class String
|
2
|
-
def to_permalink
|
3
|
-
str = ActiveSupport::Multibyte::Chars.new(self.dup)
|
4
|
-
str = str.normalize(:kd).gsub(/[^\x00-\x7F]/,'').to_s
|
5
|
-
str.gsub!(/[^-\w\d]+/xim, "-")
|
6
|
-
str.gsub!(/-+/xm, "-")
|
7
|
-
str.gsub!(/^-?(.*?)-?$/, '\1')
|
8
|
-
str.downcase!
|
9
|
-
str
|
10
|
-
end
|
11
|
-
end
|
data/lib/bookshelf/parser/txt.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
module Bookshelf
|
2
|
-
module Parser
|
3
|
-
class Txt < Base
|
4
|
-
def parse
|
5
|
-
spawn_command ["html2text", "-style", "pretty", "-nobs", "-o", txt_file.to_s, html_file.to_s]
|
6
|
-
end
|
7
|
-
|
8
|
-
def html_file
|
9
|
-
root_dir.join("output/#{name}.html")
|
10
|
-
end
|
11
|
-
|
12
|
-
def txt_file
|
13
|
-
root_dir.join("output/#{name}.txt")
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
data/lib/bookshelf/stream.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
module Bookshelf
|
2
|
-
class Stream
|
3
|
-
attr_accessor :listener, :content
|
4
|
-
attr_reader :html
|
5
|
-
|
6
|
-
def initialize(content, listener)
|
7
|
-
@content = content
|
8
|
-
@listener = listener
|
9
|
-
@html = Nokogiri::HTML.parse(content)
|
10
|
-
end
|
11
|
-
|
12
|
-
def parse
|
13
|
-
traverse(html)
|
14
|
-
end
|
15
|
-
|
16
|
-
def traverse(node)
|
17
|
-
node.children.each do |child|
|
18
|
-
emit(child)
|
19
|
-
traverse(child)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def emit(node)
|
24
|
-
listener.send(:tag, node) if node.name =~ /h[1-6]/
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
data/lib/bookshelf/syntax.rb
DELETED
@@ -1,124 +0,0 @@
|
|
1
|
-
module Bookshelf
|
2
|
-
class Syntax
|
3
|
-
autoload :Highlight, "bookshelf/syntax/highlight"
|
4
|
-
|
5
|
-
attr_reader :io
|
6
|
-
attr_reader :lines
|
7
|
-
attr_reader :book_dir
|
8
|
-
attr_reader :format
|
9
|
-
|
10
|
-
# Render syntax blocks from specified source code.
|
11
|
-
#
|
12
|
-
# dir = Pathname.new(File.dirname(__FILE__))
|
13
|
-
# text = File.read(dir.join("text/some_file.textile"))
|
14
|
-
# Bookshelf::Syntax.render(dir, :textile, text)
|
15
|
-
#
|
16
|
-
def self.render(book_dir, format, source_code, raw = false)
|
17
|
-
source_code.gsub(/@@@(.*?)@@@/m) do |match|
|
18
|
-
new(book_dir, format, $1, raw).process
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
# Process each syntax block individually.
|
23
|
-
#
|
24
|
-
def initialize(book_dir, format, code, raw = false)
|
25
|
-
@format = format
|
26
|
-
@book_dir = book_dir
|
27
|
-
@io = StringIO.new(code)
|
28
|
-
@lines = io.readlines.collect(&:chomp)
|
29
|
-
@language = 'text' if raw
|
30
|
-
end
|
31
|
-
|
32
|
-
# Return unprocessed line codes.
|
33
|
-
#
|
34
|
-
def raw
|
35
|
-
lines[1..-1].join("\n")
|
36
|
-
end
|
37
|
-
|
38
|
-
# Return meta data from syntax annotation.
|
39
|
-
#
|
40
|
-
def meta
|
41
|
-
@meta ||= begin
|
42
|
-
line = lines.first.squish
|
43
|
-
_, language, file, modifier, reference = *line.match(/^([^ ]+)(?: ([^:#]+)(?:(:|#)(.*?))?)?$/)
|
44
|
-
|
45
|
-
if modifier == "#"
|
46
|
-
type = :block
|
47
|
-
elsif modifier == ":"
|
48
|
-
type = :range
|
49
|
-
elsif file
|
50
|
-
type = :file
|
51
|
-
else
|
52
|
-
type = :inline
|
53
|
-
end
|
54
|
-
|
55
|
-
{
|
56
|
-
:language => language,
|
57
|
-
:file => file,
|
58
|
-
:type => type,
|
59
|
-
:reference => reference
|
60
|
-
}
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
# Process syntax block, returning a +pre+ HTML tag.
|
65
|
-
#
|
66
|
-
def process
|
67
|
-
code = raw.to_s.strip_heredoc
|
68
|
-
code = process_file.gsub(/\n^.*?@(begin|end):.*?$/, "") if meta[:file]
|
69
|
-
|
70
|
-
code = Highlight.apply(code, language)
|
71
|
-
|
72
|
-
# escape for textile
|
73
|
-
code = %[<notextile>#{code}</notextile>] if format == :textile
|
74
|
-
code
|
75
|
-
end
|
76
|
-
|
77
|
-
private
|
78
|
-
# Process line range as in <tt>@@@ ruby some_file.rb:15,20 @@@</tt>.
|
79
|
-
#
|
80
|
-
def process_range(code)
|
81
|
-
starts, ends = meta[:reference].split(",").collect(&:to_i)
|
82
|
-
code = StringIO.new(code).readlines[starts-1..ends-1].join("\n").strip_heredoc.chomp
|
83
|
-
end
|
84
|
-
|
85
|
-
# Process block name as in <tt>@@@ ruby some_file.rb#some_block @@@</tt>.
|
86
|
-
#
|
87
|
-
def process_block(code)
|
88
|
-
code.gsub!(/\r\n/, "\n")
|
89
|
-
re = %r[@begin: *\b(#{meta[:reference]})\b *[^\n]*\n(.*?)\n[^\n]*@end: \1]im
|
90
|
-
|
91
|
-
if code.match(re)
|
92
|
-
$2.strip_heredoc
|
93
|
-
else
|
94
|
-
"[missing '#{meta[:reference]}' block name]"
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
# Process file and its relatives.
|
99
|
-
#
|
100
|
-
def process_file
|
101
|
-
file_path = book_dir.join("code/#{meta[:file]}")
|
102
|
-
|
103
|
-
if File.exist?(file_path)
|
104
|
-
code = File.read(file_path)
|
105
|
-
|
106
|
-
if meta[:type] == :range
|
107
|
-
process_range(code)
|
108
|
-
elsif meta[:type] == :block
|
109
|
-
process_block(code)
|
110
|
-
else
|
111
|
-
code
|
112
|
-
end
|
113
|
-
else
|
114
|
-
"[missing 'code/#{meta[:file]}' file]"
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
# Return the language used for this syntax block. Overrideable
|
119
|
-
# for epub generation.
|
120
|
-
def language
|
121
|
-
@language || meta[:language]
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
data/lib/bookshelf/toc.rb
DELETED
data/lib/bookshelf/toc/epub.rb
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
module Bookshelf
|
2
|
-
module TOC
|
3
|
-
class Epub
|
4
|
-
attr_accessor :navigation
|
5
|
-
|
6
|
-
def initialize(navigation)
|
7
|
-
@navigation = navigation
|
8
|
-
end
|
9
|
-
|
10
|
-
def to_html
|
11
|
-
ERB.new(template).result OpenStruct.new(:navigation => navigation).instance_eval{ binding }
|
12
|
-
end
|
13
|
-
|
14
|
-
def template
|
15
|
-
<<-HTML.strip_heredoc.force_encoding("utf-8")
|
16
|
-
<?xml version="1.0" encoding="utf-8" ?>
|
17
|
-
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
18
|
-
<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
19
|
-
<head>
|
20
|
-
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
|
21
|
-
<link rel="stylesheet" type="text/css" href="epub.css"/>
|
22
|
-
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
|
23
|
-
<title>Table of Contents</title>
|
24
|
-
</head>
|
25
|
-
<body>
|
26
|
-
<div id="toc">
|
27
|
-
<ul>
|
28
|
-
<% navigation.each do |nav| %>
|
29
|
-
<li>
|
30
|
-
<a href="<%= nav[:content] %>"><%= nav[:label] %></a>
|
31
|
-
</li>
|
32
|
-
<% end %>
|
33
|
-
</ul>
|
34
|
-
</div>
|
35
|
-
</body>
|
36
|
-
</html>
|
37
|
-
HTML
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
data/lib/bookshelf/toc/html.rb
DELETED
@@ -1,78 +0,0 @@
|
|
1
|
-
module Bookshelf
|
2
|
-
module TOC
|
3
|
-
class HTML
|
4
|
-
# Return the table of contents in hash format.
|
5
|
-
#
|
6
|
-
attr_reader :toc
|
7
|
-
|
8
|
-
private_class_method :new
|
9
|
-
attr_reader :buffer # :nodoc:
|
10
|
-
attr_reader :attrs # :nodoc:
|
11
|
-
attr_accessor :content # :nodoc:
|
12
|
-
|
13
|
-
# Traverse every title and add a +id+ attribute.
|
14
|
-
# Return the modified content.
|
15
|
-
#
|
16
|
-
def self.normalize(content)
|
17
|
-
counter = {}
|
18
|
-
html = Nokogiri::HTML.parse(content)
|
19
|
-
html.search("h1, h2, h3, h4, h5, h6").each do |tag|
|
20
|
-
title = tag.inner_text
|
21
|
-
permalink = title.to_permalink
|
22
|
-
|
23
|
-
counter[permalink] ||= 0
|
24
|
-
counter[permalink] += 1
|
25
|
-
|
26
|
-
permalink = "#{permalink}-#{counter[permalink]}" if counter[permalink] > 1
|
27
|
-
|
28
|
-
tag.set_attribute("id", permalink)
|
29
|
-
end
|
30
|
-
|
31
|
-
html.css("body").to_xhtml.gsub(/<body>(.*?)<\/body>/m, "\\1")
|
32
|
-
end
|
33
|
-
|
34
|
-
# Traverse every title normalizing its content as a permalink.
|
35
|
-
#
|
36
|
-
def self.generate(content)
|
37
|
-
content = normalize(content)
|
38
|
-
listener = new
|
39
|
-
listener.content = content
|
40
|
-
Stream.new(content, listener).parse
|
41
|
-
listener
|
42
|
-
end
|
43
|
-
|
44
|
-
def initialize # :nodoc:
|
45
|
-
@toc = []
|
46
|
-
@counters = {}
|
47
|
-
end
|
48
|
-
|
49
|
-
def tag(node) # :nodoc:
|
50
|
-
toc << {
|
51
|
-
:level => node.name.gsub(/[^\d]/, "").to_i,
|
52
|
-
:text => node.text,
|
53
|
-
:permalink => node["id"]
|
54
|
-
}
|
55
|
-
end
|
56
|
-
|
57
|
-
# Return a hash with all normalized attributes.
|
58
|
-
#
|
59
|
-
def to_hash
|
60
|
-
{
|
61
|
-
:content => content,
|
62
|
-
:html => to_html,
|
63
|
-
:toc => toc
|
64
|
-
}
|
65
|
-
end
|
66
|
-
|
67
|
-
# Return the table of contents in HTML format.
|
68
|
-
#
|
69
|
-
def to_html
|
70
|
-
String.new.tap do |html|
|
71
|
-
toc.each do |options|
|
72
|
-
html << %[<div class="level#{options[:level]} #{options[:permalink]}"><a href="##{options[:permalink]}"><span>#{CGI.escape_html(options[:text])}</span></a></div>]
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|