arthurgeek-kitabu 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/History.txt +59 -0
  2. data/License.txt +20 -0
  3. data/README.markdown +220 -0
  4. data/Rakefile +68 -0
  5. data/TODO.txt +2 -0
  6. data/app_generators/kitabu/USAGE +5 -0
  7. data/app_generators/kitabu/kitabu_generator.rb +68 -0
  8. data/app_generators/kitabu/templates/Rakefile +3 -0
  9. data/app_generators/kitabu/templates/config.yml +8 -0
  10. data/app_generators/kitabu/templates/css/active4d.css +114 -0
  11. data/app_generators/kitabu/templates/css/blackboard.css +88 -0
  12. data/app_generators/kitabu/templates/css/dawn.css +121 -0
  13. data/app_generators/kitabu/templates/css/eiffel.css +121 -0
  14. data/app_generators/kitabu/templates/css/idle.css +62 -0
  15. data/app_generators/kitabu/templates/css/iplastic.css +80 -0
  16. data/app_generators/kitabu/templates/css/lazy.css +73 -0
  17. data/app_generators/kitabu/templates/css/mac_classic.css +123 -0
  18. data/app_generators/kitabu/templates/css/slush_poppies.css +85 -0
  19. data/app_generators/kitabu/templates/css/sunburst.css +180 -0
  20. data/app_generators/kitabu/templates/layouts/boom/layout.css +469 -0
  21. data/app_generators/kitabu/templates/layouts/boom/layout.html +37 -0
  22. data/app_generators/kitabu/templates/user.css +0 -0
  23. data/bin/kitabu +17 -0
  24. data/kitabu.gemspec +79 -0
  25. data/lib/kitabu.rb +18 -0
  26. data/lib/kitabu/base.rb +332 -0
  27. data/lib/kitabu/blackcloth.rb +165 -0
  28. data/lib/kitabu/redcloth.rb +963 -0
  29. data/lib/kitabu/tasks.rb +119 -0
  30. data/themes/active4d.css +114 -0
  31. data/themes/all_hallows_eve.css +72 -0
  32. data/themes/amy.css +147 -0
  33. data/themes/blackboard.css +88 -0
  34. data/themes/brilliance_black.css +605 -0
  35. data/themes/brilliance_dull.css +599 -0
  36. data/themes/cobalt.css +149 -0
  37. data/themes/dawn.css +121 -0
  38. data/themes/eiffel.css +121 -0
  39. data/themes/espresso_libre.css +109 -0
  40. data/themes/idle.css +62 -0
  41. data/themes/iplastic.css +80 -0
  42. data/themes/lazy.css +73 -0
  43. data/themes/mac_classic.css +123 -0
  44. data/themes/magicwb_amiga.css +104 -0
  45. data/themes/pastels_on_dark.css +188 -0
  46. data/themes/slush_poppies.css +85 -0
  47. data/themes/spacecadet.css +51 -0
  48. data/themes/sunburst.css +180 -0
  49. data/themes/twilight.css +137 -0
  50. data/themes/zenburnesque.css +91 -0
  51. metadata +144 -0
@@ -0,0 +1,37 @@
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
2
+ "http://www.w3.org/TR/html4/strict.dtd">
3
+ <html>
4
+ <head>
5
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
6
+ <link rel="stylesheet" type="text/css" href="../templates/layout.css"/>
7
+ <link rel="stylesheet" type="text/css" href="../templates/syntax.css"/>
8
+ <link rel="stylesheet" type="text/css" href="../templates/user.css"/>
9
+
10
+ <meta name="author" content="<%%= authors.join(', ') %>" />
11
+ <meta name="subject" content="<%%= subject %>" />
12
+ <meta name="keywords" content="<%%= keywords %>" />
13
+ </head>
14
+ <body>
15
+ <div class="frontcover"></div>
16
+ <div class="halftitlepage">
17
+ <h1 class="no-toc"><%%= title %></h1>
18
+ </div>
19
+
20
+ <div class="titlepage">
21
+ <h1 class="no-toc"><%%= title %></h1>
22
+ <p class="no-toc"><%%= authors.join('<br/>') %></p>
23
+ </div>
24
+
25
+ <div class="imprint">
26
+ <p><%%= copyright %></p>
27
+ </div>
28
+
29
+ <div class="chapters">
30
+ <%%= contents %>
31
+ </div>
32
+
33
+ <div class="white_page"></div>
34
+ <div class="white_page"></div>
35
+ <div class="backcover"></div>
36
+ </body>
37
+ </html>
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'rubigen'
5
+
6
+ if %w(-v --version).include? ARGV.first
7
+ require 'kitabu/version'
8
+ puts "#{File.basename($0)} #{Kitabu::VERSION::STRING}"
9
+ exit(0)
10
+ end
11
+
12
+ require 'rubigen/scripts/generate'
13
+ source = RubiGen::PathSource.new(:application,
14
+ File.join(File.dirname(__FILE__), "../app_generators"))
15
+ RubiGen::Base.reset_sources
16
+ RubiGen::Base.append_sources source
17
+ RubiGen::Scripts::Generate.new.run(ARGV, :generator => 'kitabu')
@@ -0,0 +1,79 @@
1
+ # WARNING : RAKE AUTO-GENERATED FILE. DO NOT MANUALLY EDIT!
2
+ # RUN : 'rake gem:update_gemspec'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.date = "Fri Aug 01 05:56:29 -0300 2008"
6
+ s.executables = ["kitabu"]
7
+ s.authors = ["Nando Vieira"]
8
+ s.required_rubygems_version = ">= 0"
9
+ s.version = "0.2.0"
10
+ s.files = ["Rakefile",
11
+ "kitabu.gemspec",
12
+ "History.txt",
13
+ "License.txt",
14
+ "README.markdown",
15
+ "TODO.txt",
16
+ "app_generators/kitabu",
17
+ "app_generators/kitabu/kitabu_generator.rb",
18
+ "app_generators/kitabu/templates",
19
+ "app_generators/kitabu/templates/config.yml",
20
+ "app_generators/kitabu/templates/css",
21
+ "app_generators/kitabu/templates/css/active4d.css",
22
+ "app_generators/kitabu/templates/css/blackboard.css",
23
+ "app_generators/kitabu/templates/css/dawn.css",
24
+ "app_generators/kitabu/templates/css/eiffel.css",
25
+ "app_generators/kitabu/templates/css/idle.css",
26
+ "app_generators/kitabu/templates/css/iplastic.css",
27
+ "app_generators/kitabu/templates/css/lazy.css",
28
+ "app_generators/kitabu/templates/css/mac_classic.css",
29
+ "app_generators/kitabu/templates/css/slush_poppies.css",
30
+ "app_generators/kitabu/templates/css/sunburst.css",
31
+ "app_generators/kitabu/templates/layouts",
32
+ "app_generators/kitabu/templates/layouts/boom",
33
+ "app_generators/kitabu/templates/layouts/boom/layout.css",
34
+ "app_generators/kitabu/templates/layouts/boom/layout.html",
35
+ "app_generators/kitabu/templates/Rakefile",
36
+ "app_generators/kitabu/templates/user.css",
37
+ "app_generators/kitabu/USAGE",
38
+ "bin/kitabu",
39
+ "lib/kitabu",
40
+ "lib/kitabu/base.rb",
41
+ "lib/kitabu/blackcloth.rb",
42
+ "lib/kitabu/redcloth.rb",
43
+ "lib/kitabu/tasks.rb",
44
+ "lib/kitabu.rb",
45
+ "themes/active4d.css",
46
+ "themes/all_hallows_eve.css",
47
+ "themes/amy.css",
48
+ "themes/blackboard.css",
49
+ "themes/brilliance_black.css",
50
+ "themes/brilliance_dull.css",
51
+ "themes/cobalt.css",
52
+ "themes/dawn.css",
53
+ "themes/eiffel.css",
54
+ "themes/espresso_libre.css",
55
+ "themes/idle.css",
56
+ "themes/iplastic.css",
57
+ "themes/lazy.css",
58
+ "themes/mac_classic.css",
59
+ "themes/magicwb_amiga.css",
60
+ "themes/pastels_on_dark.css",
61
+ "themes/slush_poppies.css",
62
+ "themes/spacecadet.css",
63
+ "themes/sunburst.css",
64
+ "themes/twilight.css",
65
+ "themes/zenburnesque.css"]
66
+ s.has_rdoc = false
67
+ s.requirements = ["Install the Oniguruma RE library and ultraviolet gem to get Syntax Highlighting (only for TextMate users)"]
68
+ s.email = ["fnando.vieira@gmail.com"]
69
+ s.name = "kitabu"
70
+ s.bindir = "bin"
71
+ s.homepage = "http://github.com/fnando/kitabu"
72
+ s.summary = "A framework for creating e-books from Markdown/Textile text markup using Ruby."
73
+ s.description = "A framework for creating e-books from Markdown/Textile text markup using Ruby. Using the Prince PDF generator, you'll be able to get high quality PDFs. Mac users that have Textmate installed can have source code highlighted with his favorite theme."
74
+ s.add_dependency "rubigen", ">= 0"
75
+ s.add_dependency "discount", ">= 0"
76
+ s.add_dependency "hpricot", ">= 0"
77
+ s.add_dependency "unicode", ">= 0"
78
+ s.require_paths = ["lib"]
79
+ end
@@ -0,0 +1,18 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require "rubygems"
5
+ require "yaml"
6
+ require "erb"
7
+ require "ostruct"
8
+ require "rexml/streamlistener"
9
+ require "rexml/document"
10
+ require "hpricot"
11
+
12
+ require "kitabu/base"
13
+
14
+ begin
15
+ require "ruby-debug"
16
+ rescue LoadError => e
17
+ nil
18
+ end
@@ -0,0 +1,332 @@
1
+ module Kitabu
2
+ module Markup
3
+ def self.content_for(options)
4
+ source_file = File.join(KITABU_ROOT, 'code', options[:source_file].to_s)
5
+ code = options[:code]
6
+
7
+ if options[:source_file] && File.exists?(source_file)
8
+ file = File.new(source_file)
9
+
10
+ if options[:from_line] && options[:to_line]
11
+ from_line = options[:from_line].to_i - 1
12
+ to_line = options[:to_line].to_i
13
+ offset = to_line - from_line
14
+ code = file.readlines.slice(from_line, offset).join
15
+ elsif block_name = options[:block_name]
16
+ re = %r(# ?begin: ?#{block_name} ?(?:[^\r\n]+)?\r?\n(.*?)\r?\n([^\r\n]+)?# ?end: #{block_name})sim
17
+ file.read.gsub(re) { |block| code = $1 }
18
+ else
19
+ code = file.read
20
+ code = code.gsub(/&lt;/, '<').gsub(/&gt;/, '>').gsub(/&amp;/, '&')
21
+ end
22
+ end
23
+
24
+ # no code? set to default
25
+ code ||= options[:code]
26
+
27
+ # normalize indentation
28
+ line = StringIO.new(code).readlines[0]
29
+
30
+ if line =~ /^(\t+)/
31
+ char = "\t"
32
+ size = $1.length
33
+ elsif line =~ /^( +)/
34
+ char = " "
35
+ size = $1.length
36
+ end
37
+
38
+ code.gsub! %r(^#{char}{#{size}}), "" if size.to_i > 0
39
+
40
+ # remove all line stubs
41
+ code.gsub! %r(^[\t ]*__$), ""
42
+
43
+ # return
44
+ code
45
+ end
46
+
47
+ def self.syntax(code, syntax='plain_text')
48
+ # get chosen theme
49
+ theme = Kitabu::Base.config['theme']
50
+ theme = Kitabu::Base.default_theme unless Kitabu::Base.theme?(theme)
51
+
52
+ # get syntax
53
+ syntax = Kitabu::Base.default_syntax unless Kitabu::Base.syntax?(syntax)
54
+
55
+ Uv.parse(code, "xhtml", syntax, false, theme)
56
+ end
57
+ end
58
+
59
+ module Base
60
+ DEFAULT_LAYOUT = 'boom'
61
+ DEFAULT_THEME = 'eiffel'
62
+ DEFAULT_SYNTAX = 'plain_text'
63
+ GEM_ROOT = File.expand_path(File.dirname(__FILE__) + "/../../")
64
+
65
+ def self.html_path
66
+ KITABU_ROOT + "/output/#{app_name}.html"
67
+ end
68
+
69
+ def self.pdf_path
70
+ KITABU_ROOT + "/output/#{app_name}.pdf"
71
+ end
72
+
73
+ def self.template_path
74
+ KITABU_ROOT + "/templates/layout.html"
75
+ end
76
+
77
+ def self.config_path
78
+ KITABU_ROOT + "/config.yml"
79
+ end
80
+
81
+ def self.text_dir
82
+ KITABU_ROOT + "/text"
83
+ end
84
+
85
+ def self.config
86
+ @config ||= YAML::load_file(config_path)
87
+ end
88
+
89
+ def self.parse_layout(contents)
90
+ template = File.new(template_path).read
91
+ contents, toc = self.table_of_contents(contents)
92
+ cfg = config.merge(:contents => contents, :toc => toc)
93
+ env = OpenStruct.new(cfg)
94
+
95
+ ERB.new(template).result env.instance_eval{binding}
96
+ end
97
+
98
+ def self.table_of_contents(contents)
99
+ return [contents, nil] unless Object.const_defined?('Hpricot') && Object.const_defined?('Unicode')
100
+
101
+ doc = Hpricot(contents)
102
+ counter = {}
103
+
104
+ (doc/"h2, h3, h4, h5, h6").each do |node|
105
+ title = node.inner_text
106
+ permalink = Kitabu::Base.to_permalink(title)
107
+
108
+ # initialize and increment counter
109
+ counter[permalink] ||= 0
110
+ counter[permalink] += 1
111
+
112
+ # set a incremented permalink if more than one occurrence
113
+ # is found
114
+ permalink = "#{permalink}-#{counter[permalink]}" if counter[permalink] > 1
115
+
116
+ node.set_attribute(:id, permalink)
117
+ end
118
+
119
+ contents = doc.to_html
120
+ io = StringIO.new(contents)
121
+ toc = Toc.new
122
+ REXML::Document.parse_stream(io, toc)
123
+
124
+ [contents, toc.to_s]
125
+ end
126
+
127
+ def self.generate_pdf
128
+ IO.popen('prince %s -o %s' % [html_path, pdf_path])
129
+ end
130
+
131
+ def self.generate_html
132
+ # all parsed markdown file holder
133
+ contents = ""
134
+
135
+ # first, get all chapters; then, get all parsed markdown
136
+ # files from this chapter and group them into a <div class="chapter"> tag
137
+ Dir.entries(text_dir).sort.each do |dirname|
138
+ # ignore files and some directories
139
+ next if %w(. .. .svn .git).include?(dirname) || File.file?(text_dir + "/#{dirname}")
140
+
141
+ # gets all parsed markdown files to wrap in a
142
+ # chapter element
143
+ chapter = ""
144
+
145
+ # merge all markdown and textile files into a single list
146
+ markup_files = Dir["#{text_dir}/#{dirname}/**/*.markdown"] + Dir["#{text_dir}/#{dirname}/**/*.textile"]
147
+
148
+ # no files, so skip it!
149
+ next if markup_files.empty?
150
+
151
+ markup_files.sort.each do |markup_file|
152
+ # get the file contents
153
+ markup_contents = File.new(markup_file).read
154
+
155
+ # instantiate a markup object
156
+ begin
157
+ if markup_file =~ /\.textile$/
158
+ markup = BlackCloth.new(markup_contents)
159
+ else
160
+ markup = Discount.new(markup_contents)
161
+ end
162
+ rescue Exception => e
163
+ puts "Skipping #{markup_file} (#{e.message})"
164
+ next
165
+ end
166
+
167
+ # convert the markup into html
168
+ parsed_contents = markup.to_html
169
+
170
+ if Object.const_defined?('Uv')
171
+ if markup.respond_to?(:syntax_blocks)
172
+ # textile
173
+ parsed_contents.gsub!(/@syntax:([0-9]+)/m) do |m|
174
+ syntax, code = markup.syntax_blocks[$1.to_i]
175
+ Kitabu::Markup.syntax(code, syntax)
176
+ end
177
+ else
178
+ # markdown
179
+ parsed_contents.gsub! /<pre><code>(.*?)<\/code><\/pre>/m do |block|
180
+ code = $1.gsub(/&lt;/, '<').gsub(/&gt;/, '>').gsub(/&amp;/, '&')
181
+ code_lines = StringIO.new(code).readlines
182
+ syntax_settings = code_lines.first
183
+
184
+ syntax = 'plain_text'
185
+
186
+ if syntax_settings =~ /syntax\(.*?\)\./
187
+ code = code_lines.slice(1, code_lines.size).join
188
+
189
+ # syntax
190
+ m, syntax = *syntax_settings.match(/syntax\(([^ #]+).*?\)./)
191
+
192
+ # file name
193
+ m, source_file = *syntax_settings.match(/syntax\(.*?\)\. +(.*?)$/)
194
+
195
+ # get line interval
196
+ m, from_line, to_line = *syntax_settings.match(/syntax\(.*? ([0-9]+),([0-9]+)\)/)
197
+
198
+ # get block name
199
+ m, block_name = *syntax_settings.match(/syntax\(.*?#([0-9a-z_]+)\)/)
200
+
201
+ code = Kitabu::Markup.content_for({
202
+ :code => code,
203
+ :from_line => from_line,
204
+ :to_line => to_line,
205
+ :block_name => block_name,
206
+ :source_file => source_file
207
+ })
208
+
209
+ Kitabu::Markup.syntax(code, syntax)
210
+ end
211
+ end
212
+ end
213
+ end
214
+
215
+ chapter << (parsed_contents + "\n\n")
216
+ end
217
+
218
+ contents << '<div class="chapter">%s</div>' % chapter
219
+ end
220
+
221
+ # save html file
222
+ File.open(html_path, 'w+') do |f|
223
+ f << Kitabu::Base.parse_layout(contents)
224
+ end
225
+ end
226
+
227
+ def self.app_name
228
+ ENV['KITABU_NAME'] || 'kitabu'
229
+ end
230
+
231
+ def self.theme?(theme_name)
232
+ themes.include?(theme_name)
233
+ end
234
+
235
+ def self.syntax?(syntax_name)
236
+ syntaxes.include?(syntax_name)
237
+ end
238
+
239
+ def self.default_theme
240
+ DEFAULT_THEME
241
+ end
242
+
243
+ def self.default_syntax
244
+ DEFAULT_SYNTAX
245
+ end
246
+
247
+ def self.default_layout
248
+ DEFAULT_LAYOUT
249
+ end
250
+
251
+ def self.syntaxes
252
+ Uv.syntaxes
253
+ end
254
+
255
+ def self.layouts
256
+ @layouts ||= begin
257
+ dir = File.join(GEM_ROOT, "app_generators/kitabu/templates/layouts/")
258
+ Dir.entries(dir).reject{|p| p =~ /^\.+$/ }.sort
259
+ end
260
+ end
261
+
262
+ def self.themes
263
+ @themes ||= begin
264
+ filter = File.join(GEM_ROOT, "app_generators/kitabu/templates/css/*.css")
265
+ Dir[filter].collect{|path| File.basename(path).gsub(/\.css$/, '') }.sort
266
+ end
267
+ end
268
+
269
+ def self.to_permalink(str)
270
+ str = Unicode.normalize_KD(str).gsub(/[^\x00-\x7F]/n,'')
271
+ str = str.gsub(/[^-_\s\w]/, ' ').downcase.squeeze(' ').tr(' ', '-')
272
+ str = str.gsub(/-+/, '-').gsub(/^-+/, '').gsub(/-+$/, '')
273
+ str
274
+ end
275
+ end
276
+
277
+ class Toc
278
+ include REXML::StreamListener
279
+
280
+ def initialize
281
+ @toc = ""
282
+ @previous_level = 0
283
+ @tag = nil
284
+ @stack = []
285
+ end
286
+
287
+ def header?(tag=nil)
288
+ tag ||= @tag_name
289
+ return false unless tag.to_s =~ /h[2-6]/
290
+ @tag_name = tag
291
+ return true
292
+ end
293
+
294
+ def in_header?
295
+ @in_header
296
+ end
297
+
298
+ def tag_start(name, attrs)
299
+ @tag_name = name
300
+ return unless header?(name)
301
+ @in_header = true
302
+ @current_level = name.gsub!(/[^2-6]/, '').to_i
303
+ @stack << @current_level
304
+ @id = attrs["id"]
305
+
306
+ @toc << %(<ul class="level#{@current_level}">) if @current_level > @previous_level
307
+ @toc << %(</li></ul>) * (@previous_level - @current_level) if @current_level < @previous_level
308
+ @toc << %(</li>) if @current_level <= @previous_level
309
+ @toc << %(<li>)
310
+ end
311
+
312
+ def tag_end(name)
313
+ return unless header?(name)
314
+ @in_header = false
315
+ @previous_level = @current_level
316
+ end
317
+
318
+ def text(str)
319
+ return unless in_header?
320
+ @toc << %(<a href="##{@id}"><span>#{str}</span></a>)
321
+ end
322
+
323
+ def method_missing(*args)
324
+ end
325
+
326
+ def to_s
327
+ @toc + (%(</li></ul>) * (@stack.last - 1))
328
+ rescue
329
+ ""
330
+ end
331
+ end
332
+ end