1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
require 'set'
module RailsGuides
class Generator
attr_reader :output, :view_path, :view, :guides_dir
def initialize(output = nil)
@guides_dir = File.join(File.dirname(__FILE__), '..')
@output = output || File.join(@guides_dir, "output")
unless ENV["ONLY"]
FileUtils.rm_r(@output) if File.directory?(@output)
FileUtils.mkdir(@output)
end
@view_path = File.join(@guides_dir, "source")
end
def generate
guides = Dir.entries(view_path).find_all {|g| g =~ /textile$/ }
if ENV["ONLY"]
only = ENV["ONLY"].split(",").map{|x| x.strip }.map {|o| "#{o}.textile" }
guides = guides.find_all {|g| only.include?(g) }
puts "GENERATING ONLY #{guides.inspect}"
end
guides.each do |guide|
generate_guide(guide)
end
# Copy images and css files to html directory
FileUtils.cp_r File.join(guides_dir, 'images'), File.join(output, 'images')
FileUtils.cp_r File.join(guides_dir, 'files'), File.join(output, 'files')
end
def generate_guide(guide)
guide =~ /(.*?)(\.erb)?\.textile/
name = $1
puts "Generating #{name}"
file = File.join(output, "#{name}.html")
File.open(file, 'w') do |f|
@view = ActionView::Base.new(view_path)
@view.extend(Helpers)
if guide =~ /\.erb\.textile/
# Generate the erb pages with textile formatting - e.g. index/authors
result = view.render(:layout => 'layout', :file => name)
f.write textile(result)
else
body = File.read(File.join(view_path, guide))
body = set_header_section(body, @view)
body = set_index(body, @view)
result = view.render(:layout => 'layout', :text => textile(body))
f.write result
end
end
end
def set_header_section(body, view)
new_body = body.gsub(/(.*?)endprologue\./m, '').strip
header = $1
header =~ /h2\.(.*)/
page_title = $1.strip
header = textile(header)
view.content_for(:page_title) { page_title }
view.content_for(:header_section) { header }
new_body
end
def set_index(body, view)
index = <<-INDEX
<div id="subCol">
<h3 class="chapter"><img src="images/chapters_icon.gif" alt="" />Chapters</h3>
<ol class="chapters">
INDEX
i = Indexer.new(body)
i.index
# Set index for 2 levels
i.level_hash.each do |key, value|
link = view.content_tag(:a, :href => key[:id]) { textile(key[:title]) }
children = value.keys.map do |k|
l = view.content_tag(:a, :href => k[:id]) { textile(k[:title]) }
view.content_tag(:li, l)
end
children_ul = view.content_tag(:ul, children)
index << view.content_tag(:li, link + children_ul)
end
index << '</ol>'
index << '</div>'
view.content_for(:index_section) { index }
i.result
end
def textile(body)
# If the issue with notextile is fixed just remove the wrapper.
with_workaround_for_notextile(body) do |body|
t = RedCloth.new(body)
t.hard_breaks = false
t.to_html(:notestuff, :plusplus, :code, :tip)
end
end
# For some reason the notextile tag does not always turn off textile. See
# LH ticket of the security guide (#7). As a temporary workaround we deal
# with code blocks by hand.
def with_workaround_for_notextile(body)
code_blocks = []
body.gsub!(%r{<(yaml|shell|ruby|erb|html|sql|plain)>(.*?)</\1>}m) do |m|
es = ERB::Util.h($2)
css_class = ['erb', 'shell'].include?($1) ? 'html' : $1
code_blocks << %{<div class="code_container"><code class="#{css_class}">#{es}</code></div>}
"\ndirty_workaround_for_notextile_#{code_blocks.size - 1}\n"
end
body = yield body
body.gsub(%r{<p>dirty_workaround_for_notextile_(\d+)</p>}) do |_|
code_blocks[$1.to_i]
end
end
end
end
|