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.
@@ -1,3 +0,0 @@
1
- module Bookshelf
2
- class DirectoryAlreadyCreatedError < StandardError; end
3
- end
@@ -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
@@ -1,14 +0,0 @@
1
- module Bookshelf
2
- module Parser
3
- class Mobi < Base
4
- def parse
5
- spawn_command ["kindlegen", epub_file.to_s,]
6
- true
7
- end
8
-
9
- def epub_file
10
- root_dir.join("output/#{name}.epub")
11
- end
12
- end
13
- end
14
- end
@@ -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
-
@@ -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
@@ -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
@@ -1,6 +0,0 @@
1
- module Bookshelf
2
- module TOC
3
- autoload :HTML, "bookshelf/toc/html"
4
- autoload :Epub, "bookshelf/toc/epub"
5
- end
6
- end
@@ -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
@@ -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